aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--3rdparty/python-console/modified/pyconsole.cc322
-rw-r--r--3rdparty/python-console/modified/pyconsole.h80
-rw-r--r--gui/CMakeLists.txt1
-rw-r--r--gui/basewindow.cc2
-rw-r--r--gui/line_editor.cc56
-rw-r--r--gui/line_editor.h11
-rw-r--r--gui/pyconsole.cc82
-rw-r--r--gui/pyconsole.h58
-rw-r--r--gui/pythontab.cc41
-rw-r--r--gui/pythontab.h8
10 files changed, 249 insertions, 412 deletions
diff --git a/3rdparty/python-console/modified/pyconsole.cc b/3rdparty/python-console/modified/pyconsole.cc
deleted file mode 100644
index d724553b..00000000
--- a/3rdparty/python-console/modified/pyconsole.cc
+++ /dev/null
@@ -1,322 +0,0 @@
-#include "pyconsole.h"
-#include "pyinterpreter.h"
-#include "ColumnFormatter.h"
-
-#include <iostream>
-#include <QKeyEvent>
-#include <QFont>
-
-#include "Utils.h"
-
-const QString PythonConsole::PROMPT = ">>> ";
-const QString PythonConsole::MULTILINE_PROMPT = "... ";
-const QColor PythonConsole::NORMAL_COLOR = QColor::fromRgbF( 0, 0, 0 );
-const QColor PythonConsole::ERROR_COLOR = QColor::fromRgbF( 1.0, 0, 0 );
-const QColor PythonConsole::OUTPUT_COLOR = QColor::fromRgbF( 0, 0, 1.0 );
-
-PythonConsole::PythonConsole( QWidget* parent ):
- QTextEdit( parent )
-{
- QFont font("unexistent");
- font.setStyleHint(QFont::Monospace);
- setFont(font);
- m_parseHelper.subscribe( this );
-}
-
-void PythonConsole::keyPressEvent( QKeyEvent* e )
-{
- switch ( e->key() )
- {
- case Qt::Key_Return:
- handleReturnKeyPress( );
- return;
-
- case Qt::Key_Tab:
- autocomplete( );
- return;
-
- case Qt::Key_Backspace:
- if ( ! canBackspace( ) )
- return;
- break;
-
- case Qt::Key_Up:
- previousHistory( );
- return;
-
- case Qt::Key_Down:
- nextHistory( );
- return;
-
- case Qt::Key_Left:
- if ( ! canGoLeft( ) )
- return;
- }
- if (!cursorIsOnInputLine()) return;
- if (textCursor().columnNumber() < PythonConsole::PROMPT.size()) return;
- QTextEdit::keyPressEvent( e );
-}
-
-void PythonConsole::handleReturnKeyPress( )
-{
- if ( ! cursorIsOnInputLine( ) )
- {
- return;
- }
-
- QString line = getLine( );
-
- m_parseHelper.process( line.toStdString( ) );
- if ( m_parseHelper.buffered( ) )
- {
- append("");
- displayPrompt( );
- }
- if ( line.size( ) )
- {
- m_historyBuffer.push_back( line.toStdString( ) );
- m_historyIt = m_historyBuffer.end();
- }
- moveCursorToEnd( );
-}
-
-void PythonConsole::parseEvent( const ParseMessage& message )
-{
- // handle invalid user input
- if ( message.errorCode )
- {
- setTextColor( ERROR_COLOR );
- append(message.message.c_str());
-
- setTextColor( NORMAL_COLOR );
- append("");
- displayPrompt( );
- return;
- }
-
- // interpret valid user input
- int errorCode = 0;
- std::string res;
- if ( message.message.size() )
- res = pyinterpreter_execute( message.message, &errorCode );
- if ( errorCode )
- {
- setTextColor( ERROR_COLOR );
- }
- else
- {
- setTextColor( OUTPUT_COLOR );
- }
-
- if ( res.size( ) )
- {
- append(res.c_str());
- }
-
- setTextColor( NORMAL_COLOR );
-
- // set up the next line on the console
- append("");
- displayPrompt( );
-}
-
-QString PythonConsole::getLine( )
-{
- QTextCursor cursor = textCursor();
- cursor.movePosition( QTextCursor::StartOfLine );
- cursor.movePosition( QTextCursor::Right, QTextCursor::MoveAnchor, PythonConsole::PROMPT.size( ) );
- cursor.movePosition( QTextCursor::EndOfLine, QTextCursor::KeepAnchor );
- QString line = cursor.selectedText( );
- cursor.clearSelection( );
- return line;
-}
-
-bool PythonConsole::cursorIsOnInputLine( )
-{
- int cursorBlock = textCursor( ).blockNumber( );
- QTextCursor bottomCursor = textCursor( );
- bottomCursor.movePosition( QTextCursor::End );
- int bottomBlock = bottomCursor.blockNumber( );
- return ( cursorBlock == bottomBlock );
-}
-
-bool PythonConsole::inputLineIsEmpty( )
-{
- QTextCursor bottomCursor = textCursor( );
- bottomCursor.movePosition( QTextCursor::End );
- int col = bottomCursor.columnNumber( );
- return ( col == PythonConsole::PROMPT.size( ) );
-}
-
-bool PythonConsole::canBackspace( )
-{
- if ( ! cursorIsOnInputLine( ) )
- {
- return false;
- }
-
- if ( inputLineIsEmpty( ) )
- {
- return false;
- }
-
- return true;
-}
-
-bool PythonConsole::canGoLeft( )
-{
- if ( cursorIsOnInputLine( ) )
- {
- QTextCursor bottomCursor = textCursor( );
- int col = bottomCursor.columnNumber( );
- return (col > PythonConsole::PROMPT.size( ));
- }
- return true;
-}
-
-void PythonConsole::displayPrompt( )
-{
- QTextCursor cursor = textCursor();
- cursor.movePosition( QTextCursor::End );
- if ( m_parseHelper.buffered( ) )
- {
- cursor.insertText( PythonConsole::MULTILINE_PROMPT );
- }
- else
- {
- cursor.insertText( PythonConsole::PROMPT );
- }
- cursor.movePosition( QTextCursor::EndOfLine );
-}
-
-void PythonConsole::displayString(QString text)
-{
- QTextCursor cursor = textCursor();
- cursor.movePosition( QTextCursor::End );
- cursor.insertText( text );
- cursor.movePosition( QTextCursor::EndOfLine );
-}
-
-void PythonConsole::autocomplete( )
-{
- if ( ! cursorIsOnInputLine( ) )
- return;
-
- QString line = getLine( );
- const std::list<std::string>& suggestions =
- pyinterpreter_suggest( line.toStdString( ) );
- if (suggestions.size() == 1)
- {
- line = suggestions.back().c_str();
- }
- else
- {
- // try to complete to longest common prefix
- std::string prefix =
- LongestCommonPrefix(suggestions.begin(), suggestions.end());
- if (prefix.size() > (size_t)line.size())
- {
- line = prefix.c_str();
- }
- else
- {
- ColumnFormatter fmt;
- fmt.setItems(suggestions.begin(), suggestions.end());
- fmt.format(width() / 10);
- setTextColor( OUTPUT_COLOR );
- const std::list<std::string>& formatted = fmt.formattedOutput();
- for (std::list<std::string>::const_iterator it = formatted.begin();
- it != formatted.end(); ++it)
- {
- append(it->c_str());
- }
- setTextColor( NORMAL_COLOR );
- }
- }
-
- // set up the next line on the console
- append("");
- displayPrompt( );
- moveCursorToEnd( );
- QTextCursor cursor = textCursor();
- cursor.insertText( line );
- moveCursorToEnd( );
-}
-
-void PythonConsole::previousHistory( )
-{
- if ( ! cursorIsOnInputLine( ) )
- return;
-
- if ( ! m_historyBuffer.size( ) )
- return;
-
- QTextCursor cursor = textCursor();
- cursor.movePosition( QTextCursor::StartOfLine );
- cursor.movePosition( QTextCursor::Right, QTextCursor::MoveAnchor, PythonConsole::PROMPT.size( ) );
- cursor.movePosition( QTextCursor::EndOfLine, QTextCursor::KeepAnchor );
- cursor.removeSelectedText( );
- if ( m_historyIt != m_historyBuffer.begin( ) )
- {
- --m_historyIt;
- }
- cursor.insertText( m_historyIt->c_str() );
-}
-
-void PythonConsole::nextHistory( )
-{
- if ( ! cursorIsOnInputLine( ) )
- return;
-
- if ( ! m_historyBuffer.size( ) )
- return;
- if ( m_historyIt == m_historyBuffer.end( ) )
- {
- return;
- }
- QTextCursor cursor = textCursor();
- cursor.movePosition( QTextCursor::StartOfLine );
- cursor.movePosition( QTextCursor::Right, QTextCursor::MoveAnchor, PythonConsole::PROMPT.size( ) );
- cursor.movePosition( QTextCursor::EndOfLine, QTextCursor::KeepAnchor );
- cursor.removeSelectedText( );
- ++m_historyIt;
- if ( m_historyIt == m_historyBuffer.end( ) )
- {
- return;
- }
- cursor.insertText( m_historyIt->c_str() );
-}
-
-void PythonConsole::moveCursorToEnd( )
-{
- QTextCursor cursor = textCursor();
- cursor.movePosition( QTextCursor::End );
- setTextCursor( cursor );
-}
-
-void PythonConsole::insertFromMimeData(const QMimeData *src)
-{
- if (src->hasText()) {
- QStringList list = src->text().split("\n",QString::KeepEmptyParts);
- bool lastends = src->text().endsWith("\n");
- for (int i=0;i<list.size();i++)
- {
- QString line = list.at(i);
- displayString(line);
- if (!lastends && (i==list.size()-1)) break;
-
- m_parseHelper.process( line.toStdString( ) );
- if ( m_parseHelper.buffered( ) )
- {
- append("");
- displayPrompt( );
- }
- if ( line.size( ) )
- {
- m_historyBuffer.push_back( line.toStdString( ) );
- m_historyIt = m_historyBuffer.end();
- }
- moveCursorToEnd( );
- }
- }
-} \ No newline at end of file
diff --git a/3rdparty/python-console/modified/pyconsole.h b/3rdparty/python-console/modified/pyconsole.h
deleted file mode 100644
index adf4ce20..00000000
--- a/3rdparty/python-console/modified/pyconsole.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
-python-console
-Copyright (C) 2018 Alex Tsui
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-#ifndef PYCONSOLE_H
-#define PYCONSOLE_H
-#include <QColor>
-#include <QTextEdit>
-#include <QMimeData>
-#include "ParseHelper.h"
-#include "ParseListener.h"
-
-class QWidget;
-class QKeyEvent;
-
-class PythonConsole : public QTextEdit, ParseListener
-{
- Q_OBJECT
-
- public:
- PythonConsole(QWidget *parent = 0);
-
- void displayPrompt();
- void displayString(QString text);
-
- protected:
- // override QTextEdit
- virtual void keyPressEvent(QKeyEvent *e);
-
- virtual void handleReturnKeyPress();
-
- virtual void insertFromMimeData(const QMimeData *src);
-
- /**
- Handle a compilable chunk of Python user input.
- */
- virtual void parseEvent(const ParseMessage &message);
-
- QString getLine();
- bool cursorIsOnInputLine();
- bool inputLineIsEmpty();
- bool canBackspace();
- bool canGoLeft();
- void autocomplete();
- void previousHistory();
- void nextHistory();
- void moveCursorToEnd();
-
- static const QString PROMPT;
- static const QString MULTILINE_PROMPT;
-
- static const QColor NORMAL_COLOR;
- static const QColor ERROR_COLOR;
- static const QColor OUTPUT_COLOR;
-
- ParseHelper m_parseHelper;
- std::list<std::string> m_historyBuffer;
- std::list<std::string>::const_iterator m_historyIt;
-};
-
-#endif // PYCONSOLE_H
diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt
index 5ac4d955..2e8e367e 100644
--- a/gui/CMakeLists.txt
+++ b/gui/CMakeLists.txt
@@ -12,7 +12,6 @@ if (BUILD_PYTHON)
../3rdparty/python-console/modified/pyredirector.cc
../3rdparty/python-console/modified/pyinterpreter.cc
- ../3rdparty/python-console/modified/pyconsole.cc
)
endif()
diff --git a/gui/basewindow.cc b/gui/basewindow.cc
index fd9d36f4..b76527e1 100644
--- a/gui/basewindow.cc
+++ b/gui/basewindow.cc
@@ -76,7 +76,7 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr<Context> context, QWidget *parent
tabWidget = new QTabWidget();
#ifndef NO_PYTHON
PythonTab *pythontab = new PythonTab();
- tabWidget->addTab(pythontab, "Python");
+ tabWidget->addTab(pythontab, "Console");
connect(this, SIGNAL(contextChanged(Context *)), pythontab, SLOT(newContext(Context *)));
#endif
info = new InfoTab();
diff --git a/gui/line_editor.cc b/gui/line_editor.cc
index 9d9dac25..3c7ebe94 100644
--- a/gui/line_editor.cc
+++ b/gui/line_editor.cc
@@ -2,6 +2,7 @@
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 Miodrag Milanovic <miodrag@symbioticeda.com>
+ * Copyright (C) 2018 Alex Tsui
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -17,12 +18,18 @@
*
*/
+#ifndef NO_PYTHON
+
#include "line_editor.h"
#include <QKeyEvent>
+#include <QToolTip>
+#include "ColumnFormatter.h"
+#include "Utils.h"
+#include "pyinterpreter.h"
NEXTPNR_NAMESPACE_BEGIN
-LineEditor::LineEditor(QWidget *parent) : QLineEdit(parent), index(0)
+LineEditor::LineEditor(ParseHelper *helper, QWidget *parent) : QLineEdit(parent), index(0), parseHelper(helper)
{
setContextMenuPolicy(Qt::CustomContextMenu);
QAction *clearAction = new QAction("Clear &history", this);
@@ -38,10 +45,12 @@ LineEditor::LineEditor(QWidget *parent) : QLineEdit(parent), index(0)
void LineEditor::keyPressEvent(QKeyEvent *ev)
{
+
if (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) {
+ QToolTip::hideText();
if (lines.empty())
return;
-
+ printf("Key_Up\n");
if (ev->key() == Qt::Key_Up)
index--;
if (ev->key() == Qt::Key_Down)
@@ -56,12 +65,21 @@ void LineEditor::keyPressEvent(QKeyEvent *ev)
}
setText(lines[index]);
} else if (ev->key() == Qt::Key_Escape) {
+ QToolTip::hideText();
clear();
return;
+ } else if (ev->key() == Qt::Key_Tab) {
+ autocomplete();
+ return;
}
+ QToolTip::hideText();
+
QLineEdit::keyPressEvent(ev);
}
+// This makes TAB work
+bool LineEditor::focusNextPrevChild(bool next) { return false; }
+
void LineEditor::textInserted()
{
if (lines.empty() || lines.back() != text())
@@ -82,4 +100,36 @@ void LineEditor::clearHistory()
clear();
}
-NEXTPNR_NAMESPACE_END \ No newline at end of file
+void LineEditor::autocomplete()
+{
+ QString line = text();
+ const std::list<std::string> &suggestions = pyinterpreter_suggest(line.toStdString());
+ if (suggestions.size() == 1) {
+ line = suggestions.back().c_str();
+ } else {
+ // try to complete to longest common prefix
+ std::string prefix = LongestCommonPrefix(suggestions.begin(), suggestions.end());
+ if (prefix.size() > (size_t)line.size()) {
+ line = prefix.c_str();
+ } else {
+ ColumnFormatter fmt;
+ fmt.setItems(suggestions.begin(), suggestions.end());
+ fmt.format(width() / 5);
+ QString out = "";
+ for (auto &it : fmt.formattedOutput()) {
+ if (!out.isEmpty())
+ out += "\n";
+ out += it.c_str();
+ }
+ QToolTip::setFont(font());
+ if (!out.trimmed().isEmpty())
+ QToolTip::showText(mapToGlobal(QPoint(0, 0)), out);
+ }
+ }
+ // set up the next line on the console
+ setText(line);
+}
+
+NEXTPNR_NAMESPACE_END
+
+#endif // NO_PYTHON
diff --git a/gui/line_editor.h b/gui/line_editor.h
index 91837182..5a57129b 100644
--- a/gui/line_editor.h
+++ b/gui/line_editor.h
@@ -2,6 +2,7 @@
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 Miodrag Milanovic <miodrag@symbioticeda.com>
+ * Copyright (C) 2018 Alex Tsui
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -20,8 +21,11 @@
#ifndef LINE_EDITOR_H
#define LINE_EDITOR_H
+#ifndef NO_PYTHON
+
#include <QLineEdit>
#include <QMenu>
+#include "ParseHelper.h"
#include "nextpnr.h"
NEXTPNR_NAMESPACE_BEGIN
@@ -31,7 +35,7 @@ class LineEditor : public QLineEdit
Q_OBJECT
public:
- explicit LineEditor(QWidget *parent = 0);
+ explicit LineEditor(ParseHelper *helper, QWidget *parent = 0);
private Q_SLOTS:
void textInserted();
@@ -43,13 +47,18 @@ class LineEditor : public QLineEdit
protected:
void keyPressEvent(QKeyEvent *) Q_DECL_OVERRIDE;
+ bool focusNextPrevChild(bool next) Q_DECL_OVERRIDE;
+ void autocomplete();
private:
int index;
QStringList lines;
QMenu *contextMenu;
+ ParseHelper *parseHelper;
};
NEXTPNR_NAMESPACE_END
+#endif // NO_PYTHON
+
#endif // LINE_EDITOR_H
diff --git a/gui/pyconsole.cc b/gui/pyconsole.cc
new file mode 100644
index 00000000..6da06b7e
--- /dev/null
+++ b/gui/pyconsole.cc
@@ -0,0 +1,82 @@
+/*
+ * nextpnr -- Next Generation Place and Route
+ *
+ * Copyright (C) 2018 Miodrag Milanovic <miodrag@symbioticeda.com>
+ * Copyright (C) 2018 Alex Tsui
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef NO_PYTHON
+
+#include "pyconsole.h"
+#include "pyinterpreter.h"
+
+NEXTPNR_NAMESPACE_BEGIN
+
+const QColor PythonConsole::NORMAL_COLOR = QColor::fromRgbF(0, 0, 0);
+const QColor PythonConsole::ERROR_COLOR = QColor::fromRgbF(1.0, 0, 0);
+const QColor PythonConsole::OUTPUT_COLOR = QColor::fromRgbF(0, 0, 1.0);
+
+PythonConsole::PythonConsole(QWidget *parent) : QTextEdit(parent) {}
+
+void PythonConsole::parseEvent(const ParseMessage &message)
+{
+ // handle invalid user input
+ if (message.errorCode) {
+ setTextColor(ERROR_COLOR);
+ append(message.message.c_str());
+
+ setTextColor(NORMAL_COLOR);
+ append("");
+ return;
+ }
+ // interpret valid user input
+ int errorCode = 0;
+ std::string res;
+ if (message.message.size())
+ res = pyinterpreter_execute(message.message, &errorCode);
+ if (errorCode) {
+ setTextColor(ERROR_COLOR);
+ } else {
+ setTextColor(OUTPUT_COLOR);
+ }
+
+ if (res.size()) {
+ append(res.c_str());
+ }
+ setTextColor(NORMAL_COLOR);
+ append("");
+ moveCursorToEnd();
+}
+
+void PythonConsole::displayString(QString text)
+{
+ QTextCursor cursor = textCursor();
+ cursor.movePosition(QTextCursor::End);
+ setTextColor(NORMAL_COLOR);
+ cursor.insertText(text);
+ cursor.movePosition(QTextCursor::EndOfLine);
+}
+
+void PythonConsole::moveCursorToEnd()
+{
+ QTextCursor cursor = textCursor();
+ cursor.movePosition(QTextCursor::End);
+ setTextCursor(cursor);
+}
+
+NEXTPNR_NAMESPACE_END
+
+#endif // NO_PYTHON
diff --git a/gui/pyconsole.h b/gui/pyconsole.h
new file mode 100644
index 00000000..60f10672
--- /dev/null
+++ b/gui/pyconsole.h
@@ -0,0 +1,58 @@
+/*
+ * nextpnr -- Next Generation Place and Route
+ *
+ * Copyright (C) 2018 Miodrag Milanovic <miodrag@symbioticeda.com>
+ * Copyright (C) 2018 Alex Tsui
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef PYCONSOLE_H
+#define PYCONSOLE_H
+
+#ifndef NO_PYTHON
+
+#include <QColor>
+#include <QMimeData>
+#include <QTextEdit>
+#include "ParseHelper.h"
+#include "ParseListener.h"
+#include "nextpnr.h"
+
+class QWidget;
+class QKeyEvent;
+
+NEXTPNR_NAMESPACE_BEGIN
+
+class PythonConsole : public QTextEdit, public ParseListener
+{
+ Q_OBJECT
+
+ public:
+ PythonConsole(QWidget *parent = 0);
+
+ void displayString(QString text);
+ void moveCursorToEnd();
+ virtual void parseEvent(const ParseMessage &message);
+
+ protected:
+ static const QColor NORMAL_COLOR;
+ static const QColor ERROR_COLOR;
+ static const QColor OUTPUT_COLOR;
+};
+
+NEXTPNR_NAMESPACE_END
+#endif // NO_PYTHON
+
+#endif // PYCONSOLE_H
diff --git a/gui/pythontab.cc b/gui/pythontab.cc
index 897f87b3..5c349d7c 100644
--- a/gui/pythontab.cc
+++ b/gui/pythontab.cc
@@ -25,12 +25,20 @@
NEXTPNR_NAMESPACE_BEGIN
+const QString PythonTab::PROMPT = ">>> ";
+const QString PythonTab::MULTILINE_PROMPT = "... ";
+
PythonTab::PythonTab(QWidget *parent) : QWidget(parent), initialized(false)
{
+ QFont f("unexistent");
+ f.setStyleHint(QFont::Monospace);
+
// Add text area for Python output and input line
console = new PythonConsole();
console->setMinimumHeight(100);
- console->setEnabled(false);
+ console->setReadOnly(true);
+ console->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
+ console->setFont(f);
console->setContextMenuPolicy(Qt::CustomContextMenu);
QAction *clearAction = new QAction("Clear &buffer", this);
@@ -41,9 +49,21 @@ PythonTab::PythonTab(QWidget *parent) : QWidget(parent), initialized(false)
contextMenu->addAction(clearAction);
connect(console, SIGNAL(customContextMenuRequested(const QPoint)), this, SLOT(showContextMenu(const QPoint)));
+ lineEdit = new LineEditor(&parseHelper);
+ lineEdit->setMinimumHeight(30);
+ lineEdit->setMaximumHeight(30);
+ lineEdit->setFont(f);
+ lineEdit->setPlaceholderText(PythonTab::PROMPT);
+ connect(lineEdit, SIGNAL(textLineInserted(QString)), this, SLOT(editLineReturnPressed(QString)));
+
QGridLayout *mainLayout = new QGridLayout();
mainLayout->addWidget(console, 0, 0);
+ mainLayout->addWidget(lineEdit, 1, 0);
setLayout(mainLayout);
+
+ parseHelper.subscribe(console);
+
+ prompt = PythonTab::PROMPT;
}
PythonTab::~PythonTab()
@@ -54,13 +74,27 @@ PythonTab::~PythonTab()
}
}
+void PythonTab::editLineReturnPressed(QString text)
+{
+ console->displayString(prompt + text + "\n");
+ console->moveCursorToEnd();
+
+ parseHelper.process(text.toStdString());
+
+ if (parseHelper.buffered())
+ prompt = PythonTab::MULTILINE_PROMPT;
+ else
+ prompt = PythonTab::PROMPT;
+
+ lineEdit->setPlaceholderText(prompt);
+}
+
void PythonTab::newContext(Context *ctx)
{
if (initialized) {
pyinterpreter_finalize();
deinit_python();
}
- console->setEnabled(true);
console->clear();
pyinterpreter_preinit();
@@ -74,7 +108,6 @@ void PythonTab::newContext(Context *ctx)
QString version = QString("Python %1 on %2\n").arg(Py_GetVersion(), Py_GetPlatform());
console->displayString(version);
- console->displayPrompt();
}
void PythonTab::showContextMenu(const QPoint &pt) { contextMenu->exec(mapToGlobal(pt)); }
@@ -83,4 +116,4 @@ void PythonTab::clearBuffer() { console->clear(); }
NEXTPNR_NAMESPACE_END
-#endif \ No newline at end of file
+#endif // NO_PYTHON
diff --git a/gui/pythontab.h b/gui/pythontab.h
index 4b22e6a9..3fd12981 100644
--- a/gui/pythontab.h
+++ b/gui/pythontab.h
@@ -25,6 +25,7 @@
#include <QLineEdit>
#include <QMenu>
#include <QPlainTextEdit>
+#include "ParseHelper.h"
#include "line_editor.h"
#include "nextpnr.h"
#include "pyconsole.h"
@@ -42,13 +43,20 @@ class PythonTab : public QWidget
private Q_SLOTS:
void showContextMenu(const QPoint &pt);
void clearBuffer();
+ void editLineReturnPressed(QString text);
public Q_SLOTS:
void newContext(Context *ctx);
private:
PythonConsole *console;
+ LineEditor *lineEdit;
QMenu *contextMenu;
bool initialized;
+ ParseHelper parseHelper;
+ QString prompt;
+
+ static const QString PROMPT;
+ static const QString MULTILINE_PROMPT;
};
NEXTPNR_NAMESPACE_END