forked from qt-creator/qt-creator
Terminal: Create Terminal solution
Change-Id: If271fd23a84c49bbc25fcc3b9bc0939c7237d095 Reviewed-by: Cristian Adam <cristian.adam@qt.io>
This commit is contained in:
@@ -1,2 +1,3 @@
|
|||||||
add_subdirectory(spinner)
|
add_subdirectory(spinner)
|
||||||
add_subdirectory(tasking)
|
add_subdirectory(tasking)
|
||||||
|
add_subdirectory(terminal)
|
||||||
|
12
src/libs/solutions/terminal/CMakeLists.txt
Normal file
12
src/libs/solutions/terminal/CMakeLists.txt
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
add_qtc_library(TerminalLib
|
||||||
|
DEPENDS Qt::Core Qt::Widgets libvterm
|
||||||
|
SOURCES
|
||||||
|
celliterator.cpp celliterator.h
|
||||||
|
glyphcache.cpp glyphcache.h
|
||||||
|
keys.cpp keys.h
|
||||||
|
scrollback.cpp scrollback.h
|
||||||
|
surfaceintegration.h
|
||||||
|
terminal_global.h
|
||||||
|
terminalsurface.cpp terminalsurface.h
|
||||||
|
terminalview.cpp terminalview.h
|
||||||
|
)
|
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace Terminal::Internal {
|
namespace TerminalSolution {
|
||||||
|
|
||||||
CellIterator::CellIterator(const TerminalSurface *surface, QPoint pos)
|
CellIterator::CellIterator(const TerminalSurface *surface, QPoint pos)
|
||||||
: CellIterator(surface, pos.x() + (pos.y() * surface->liveSize().width()))
|
: CellIterator(surface, pos.x() + (pos.y() * surface->liveSize().width()))
|
||||||
@@ -91,4 +91,4 @@ CellIterator &CellIterator::operator+=(int n)
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Terminal::Internal
|
} // namespace TerminalSolution
|
@@ -3,15 +3,17 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "terminal_global.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <QPoint>
|
#include <QPoint>
|
||||||
|
|
||||||
namespace Terminal::Internal {
|
namespace TerminalSolution {
|
||||||
|
|
||||||
class TerminalSurface;
|
class TerminalSurface;
|
||||||
|
|
||||||
class CellIterator
|
class TERMINAL_EXPORT CellIterator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using iterator_category = std::bidirectional_iterator_tag;
|
using iterator_category = std::bidirectional_iterator_tag;
|
||||||
@@ -94,4 +96,4 @@ private:
|
|||||||
mutable std::u32string::value_type m_char;
|
mutable std::u32string::value_type m_char;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Terminal::Internal
|
} // namespace TerminalSolution
|
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#include <QTextLayout>
|
#include <QTextLayout>
|
||||||
|
|
||||||
namespace Terminal::Internal {
|
namespace TerminalSolution {
|
||||||
|
|
||||||
size_t qHash(const GlyphCacheKey &key, size_t seed = 0)
|
size_t qHash(const GlyphCacheKey &key, size_t seed = 0)
|
||||||
{
|
{
|
||||||
@@ -45,4 +45,4 @@ const QGlyphRun *GlyphCache::get(const QFont &font, const QString &text)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Terminal::Internal
|
} // namespace TerminalSolution
|
@@ -8,7 +8,7 @@
|
|||||||
#include <QGlyphRun>
|
#include <QGlyphRun>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
namespace Terminal::Internal {
|
namespace TerminalSolution {
|
||||||
|
|
||||||
struct GlyphCacheKey
|
struct GlyphCacheKey
|
||||||
{
|
{
|
||||||
@@ -31,4 +31,4 @@ public:
|
|||||||
const QGlyphRun *get(const QFont &font, const QString &text);
|
const QGlyphRun *get(const QFont &font, const QString &text);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Terminal::Internal
|
} // namespace TerminalSolution
|
@@ -1,11 +1,9 @@
|
|||||||
// Copyright (C) 2022 The Qt Company Ltd.
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
#include <utils/hostosinfo.h>
|
|
||||||
|
|
||||||
#include "keys.h"
|
#include "keys.h"
|
||||||
|
|
||||||
namespace Terminal::Internal {
|
namespace TerminalSolution {
|
||||||
|
|
||||||
VTermModifier qtModifierToVTerm(Qt::KeyboardModifiers mod)
|
VTermModifier qtModifierToVTerm(Qt::KeyboardModifiers mod)
|
||||||
{
|
{
|
||||||
@@ -77,8 +75,9 @@ VTermKey qtKeyToVTerm(Qt::Key key, bool keypad)
|
|||||||
case Qt::Key_Enter: {
|
case Qt::Key_Enter: {
|
||||||
VTermKey enterKey = VTERM_KEY_KP_ENTER;
|
VTermKey enterKey = VTERM_KEY_KP_ENTER;
|
||||||
|
|
||||||
if (Utils::HostOsInfo::isWindowsHost())
|
#ifdef Q_OS_WIN
|
||||||
enterKey = VTERM_KEY_ENTER;
|
enterKey = VTERM_KEY_ENTER;
|
||||||
|
#endif
|
||||||
|
|
||||||
return keypad ? enterKey : VTERM_KEY_NONE;
|
return keypad ? enterKey : VTERM_KEY_NONE;
|
||||||
}
|
}
|
||||||
@@ -88,4 +87,4 @@ VTermKey qtKeyToVTerm(Qt::Key key, bool keypad)
|
|||||||
return VTERM_KEY_NONE;
|
return VTERM_KEY_NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace Terminal::Internal
|
} // namespace TerminalSolution
|
@@ -7,9 +7,9 @@
|
|||||||
|
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
|
|
||||||
namespace Terminal::Internal {
|
namespace TerminalSolution {
|
||||||
|
|
||||||
VTermKey qtKeyToVTerm(Qt::Key key, bool keypad);
|
VTermKey qtKeyToVTerm(Qt::Key key, bool keypad);
|
||||||
VTermModifier qtModifierToVTerm(Qt::KeyboardModifiers mod);
|
VTermModifier qtModifierToVTerm(Qt::KeyboardModifiers mod);
|
||||||
|
|
||||||
} // namespace Terminal::Internal
|
} // namespace TerminalSolution
|
@@ -8,7 +8,7 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <future>
|
#include <future>
|
||||||
|
|
||||||
namespace Terminal::Internal {
|
namespace TerminalSolution {
|
||||||
|
|
||||||
Scrollback::Line::Line(int cols, const VTermScreenCell *cells)
|
Scrollback::Line::Line(int cols, const VTermScreenCell *cells)
|
||||||
: m_cols(cols)
|
: m_cols(cols)
|
||||||
@@ -58,4 +58,4 @@ void Scrollback::clear()
|
|||||||
m_deque.clear();
|
m_deque.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Terminal::Internal
|
} // namespace TerminalSolution
|
@@ -13,7 +13,7 @@
|
|||||||
#include <QFont>
|
#include <QFont>
|
||||||
#include <QTextLayout>
|
#include <QTextLayout>
|
||||||
|
|
||||||
namespace Terminal::Internal {
|
namespace TerminalSolution {
|
||||||
|
|
||||||
class Scrollback
|
class Scrollback
|
||||||
{
|
{
|
||||||
@@ -54,4 +54,4 @@ private:
|
|||||||
std::deque<Line> m_deque;
|
std::deque<Line> m_deque;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Terminal::Internal
|
} // namespace TerminalSolution
|
19
src/libs/solutions/terminal/surfaceintegration.h
Normal file
19
src/libs/solutions/terminal/surfaceintegration.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
namespace TerminalSolution {
|
||||||
|
|
||||||
|
class SurfaceIntegration
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void onOsc(int cmd, std::string_view str, bool initial, bool final) = 0;
|
||||||
|
|
||||||
|
virtual void onBell() {}
|
||||||
|
virtual void onTitle(const QString &title) { Q_UNUSED(title); }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace TerminalSolution
|
14
src/libs/solutions/terminal/terminal_global.h
Normal file
14
src/libs/solutions/terminal/terminal_global.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <qglobal.h>
|
||||||
|
|
||||||
|
#if defined(TERMINALLIB_LIBRARY)
|
||||||
|
#define TERMINAL_EXPORT Q_DECL_EXPORT
|
||||||
|
#elif defined(TERMINALLIB_STATIC_LIBRARY)
|
||||||
|
#define TERMINAL_EXPORT
|
||||||
|
#else
|
||||||
|
#define TERMINAL_EXPORT Q_DECL_IMPORT
|
||||||
|
#endif
|
@@ -2,17 +2,16 @@
|
|||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
#include "terminalsurface.h"
|
#include "terminalsurface.h"
|
||||||
|
#include "surfaceintegration.h"
|
||||||
|
|
||||||
#include "keys.h"
|
#include "keys.h"
|
||||||
#include "scrollback.h"
|
#include "scrollback.h"
|
||||||
|
|
||||||
#include <utils/qtcassert.h>
|
|
||||||
|
|
||||||
#include <vterm.h>
|
#include <vterm.h>
|
||||||
|
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
|
|
||||||
namespace Terminal::Internal {
|
namespace TerminalSolution {
|
||||||
|
|
||||||
Q_LOGGING_CATEGORY(log, "qtc.terminal.surface", QtWarningMsg);
|
Q_LOGGING_CATEGORY(log, "qtc.terminal.surface", QtWarningMsg);
|
||||||
|
|
||||||
@@ -23,13 +22,10 @@ QColor toQColor(const VTermColor &c)
|
|||||||
|
|
||||||
struct TerminalSurfacePrivate
|
struct TerminalSurfacePrivate
|
||||||
{
|
{
|
||||||
TerminalSurfacePrivate(TerminalSurface *surface,
|
TerminalSurfacePrivate(TerminalSurface *surface, const QSize &initialGridSize)
|
||||||
const QSize &initialGridSize,
|
|
||||||
ShellIntegration *shellIntegration)
|
|
||||||
: m_vterm(vterm_new(initialGridSize.height(), initialGridSize.width()), vterm_free)
|
: m_vterm(vterm_new(initialGridSize.height(), initialGridSize.width()), vterm_free)
|
||||||
, m_vtermScreen(vterm_obtain_screen(m_vterm.get()))
|
, m_vtermScreen(vterm_obtain_screen(m_vterm.get()))
|
||||||
, m_scrollback(std::make_unique<Internal::Scrollback>(5000))
|
, m_scrollback(std::make_unique<Scrollback>(5000))
|
||||||
, m_shellIntegration(shellIntegration)
|
|
||||||
, q(surface)
|
, q(surface)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@@ -74,7 +70,8 @@ struct TerminalSurfacePrivate
|
|||||||
};
|
};
|
||||||
m_vtermScreenCallbacks.bell = [](void *user) {
|
m_vtermScreenCallbacks.bell = [](void *user) {
|
||||||
auto p = static_cast<TerminalSurfacePrivate *>(user);
|
auto p = static_cast<TerminalSurfacePrivate *>(user);
|
||||||
emit p->q->bell();
|
if (p->m_surfaceIntegration)
|
||||||
|
p->m_surfaceIntegration->onBell();
|
||||||
return 1;
|
return 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -219,8 +216,12 @@ struct TerminalSurfacePrivate
|
|||||||
|
|
||||||
int osc(int cmd, const VTermStringFragment &fragment)
|
int osc(int cmd, const VTermStringFragment &fragment)
|
||||||
{
|
{
|
||||||
if (m_shellIntegration)
|
if (m_surfaceIntegration) {
|
||||||
m_shellIntegration->onOsc(cmd, fragment);
|
m_surfaceIntegration->onOsc(cmd,
|
||||||
|
{fragment.str, fragment.len},
|
||||||
|
fragment.initial,
|
||||||
|
fragment.final);
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -249,7 +250,8 @@ struct TerminalSurfacePrivate
|
|||||||
case VTERM_PROP_ICONNAME:
|
case VTERM_PROP_ICONNAME:
|
||||||
break;
|
break;
|
||||||
case VTERM_PROP_TITLE:
|
case VTERM_PROP_TITLE:
|
||||||
emit q->titleChanged(QString::fromUtf8(val->string.str, val->string.len));
|
if (m_surfaceIntegration)
|
||||||
|
m_surfaceIntegration->onTitle(QString::fromUtf8(val->string.str, val->string.len));
|
||||||
break;
|
break;
|
||||||
case VTERM_PROP_ALTSCREEN:
|
case VTERM_PROP_ALTSCREEN:
|
||||||
m_altscreen = val->boolean;
|
m_altscreen = val->boolean;
|
||||||
@@ -278,8 +280,11 @@ struct TerminalSurfacePrivate
|
|||||||
|
|
||||||
const VTermScreenCell *cellAt(int x, int y)
|
const VTermScreenCell *cellAt(int x, int y)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(y >= 0 && x >= 0, return nullptr);
|
if (y < 0 || x < 0 || y >= q->fullSize().height() || x >= liveSize().width()) {
|
||||||
QTC_ASSERT(y < q->fullSize().height() && x < liveSize().width(), return nullptr);
|
qCWarning(log) << "Invalid Parameter for cellAt:" << x << y << "liveSize:" << liveSize()
|
||||||
|
<< "fullSize:" << q->fullSize();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
if (!m_altscreen && y < m_scrollback->size()) {
|
if (!m_altscreen && y < m_scrollback->size()) {
|
||||||
const auto &sbl = m_scrollback->line((m_scrollback->size() - 1) - y);
|
const auto &sbl = m_scrollback->line((m_scrollback->size() - 1) - y);
|
||||||
@@ -309,15 +314,15 @@ struct TerminalSurfacePrivate
|
|||||||
|
|
||||||
bool m_altscreen{false};
|
bool m_altscreen{false};
|
||||||
|
|
||||||
std::unique_ptr<Internal::Scrollback> m_scrollback;
|
std::unique_ptr<Scrollback> m_scrollback;
|
||||||
|
|
||||||
ShellIntegration *m_shellIntegration{nullptr};
|
SurfaceIntegration *m_surfaceIntegration{nullptr};
|
||||||
|
|
||||||
TerminalSurface *q;
|
TerminalSurface *q;
|
||||||
};
|
};
|
||||||
|
|
||||||
TerminalSurface::TerminalSurface(QSize initialGridSize, ShellIntegration *shellIntegration)
|
TerminalSurface::TerminalSurface(QSize initialGridSize)
|
||||||
: d(std::make_unique<TerminalSurfacePrivate>(this, initialGridSize, shellIntegration))
|
: d(std::make_unique<TerminalSurfacePrivate>(this, initialGridSize))
|
||||||
{
|
{
|
||||||
d->init();
|
d->init();
|
||||||
}
|
}
|
||||||
@@ -369,8 +374,10 @@ TerminalCell TerminalSurface::fetchCell(int x, int y) const
|
|||||||
QTextCharFormat::NoUnderline,
|
QTextCharFormat::NoUnderline,
|
||||||
false};
|
false};
|
||||||
|
|
||||||
QTC_ASSERT(y >= 0, return emptyCell);
|
if (y < 0 || y >= fullSize().height() || x >= fullSize().width()) {
|
||||||
QTC_ASSERT(y < fullSize().height() && x < fullSize().width(), return emptyCell);
|
qCWarning(log) << "Invalid Parameter for fetchCell:" << x << y << "fullSize:" << fullSize();
|
||||||
|
return emptyCell;
|
||||||
|
}
|
||||||
|
|
||||||
const VTermScreenCell *refCell = d->cellAt(x, y);
|
const VTermScreenCell *refCell = d->cellAt(x, y);
|
||||||
if (!refCell)
|
if (!refCell)
|
||||||
@@ -450,8 +457,8 @@ void TerminalSurface::sendKey(const QString &text)
|
|||||||
void TerminalSurface::sendKey(QKeyEvent *event)
|
void TerminalSurface::sendKey(QKeyEvent *event)
|
||||||
{
|
{
|
||||||
bool keypad = event->modifiers() & Qt::KeypadModifier;
|
bool keypad = event->modifiers() & Qt::KeypadModifier;
|
||||||
VTermModifier mod = Internal::qtModifierToVTerm(event->modifiers());
|
VTermModifier mod = qtModifierToVTerm(event->modifiers());
|
||||||
VTermKey key = Internal::qtKeyToVTerm(Qt::Key(event->key()), keypad);
|
VTermKey key = qtKeyToVTerm(Qt::Key(event->key()), keypad);
|
||||||
|
|
||||||
if (key != VTERM_KEY_NONE) {
|
if (key != VTERM_KEY_NONE) {
|
||||||
if (mod == VTERM_MOD_SHIFT && (key == VTERM_KEY_ESCAPE || key == VTERM_KEY_BACKSPACE))
|
if (mod == VTERM_MOD_SHIFT && (key == VTERM_KEY_ESCAPE || key == VTERM_KEY_BACKSPACE))
|
||||||
@@ -489,14 +496,19 @@ Cursor TerminalSurface::cursor() const
|
|||||||
return cursor;
|
return cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShellIntegration *TerminalSurface::shellIntegration() const
|
SurfaceIntegration *TerminalSurface::surfaceIntegration() const
|
||||||
{
|
{
|
||||||
return d->m_shellIntegration;
|
return d->m_surfaceIntegration;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerminalSurface::setSurfaceIntegration(SurfaceIntegration *surfaceIntegration)
|
||||||
|
{
|
||||||
|
d->m_surfaceIntegration = surfaceIntegration;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerminalSurface::mouseMove(QPoint pos, Qt::KeyboardModifiers modifiers)
|
void TerminalSurface::mouseMove(QPoint pos, Qt::KeyboardModifiers modifiers)
|
||||||
{
|
{
|
||||||
vterm_mouse_move(d->m_vterm.get(), pos.y(), pos.x(), Internal::qtModifierToVTerm(modifiers));
|
vterm_mouse_move(d->m_vterm.get(), pos.y(), pos.x(), qtModifierToVTerm(modifiers));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerminalSurface::mouseButton(Qt::MouseButton button,
|
void TerminalSurface::mouseButton(Qt::MouseButton button,
|
||||||
@@ -524,7 +536,7 @@ void TerminalSurface::mouseButton(Qt::MouseButton button,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
vterm_mouse_button(d->m_vterm.get(), btnIdx, pressed, Internal::qtModifierToVTerm(modifiers));
|
vterm_mouse_button(d->m_vterm.get(), btnIdx, pressed, qtModifierToVTerm(modifiers));
|
||||||
}
|
}
|
||||||
|
|
||||||
CellIterator TerminalSurface::begin() const
|
CellIterator TerminalSurface::begin() const
|
||||||
@@ -568,4 +580,4 @@ std::reverse_iterator<CellIterator> TerminalSurface::rIteratorAt(int pos) const
|
|||||||
return std::make_reverse_iterator(iteratorAt(pos));
|
return std::make_reverse_iterator(iteratorAt(pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Terminal::Internal
|
} // namespace TerminalSolution
|
@@ -3,8 +3,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "terminal_global.h"
|
||||||
|
|
||||||
#include "celliterator.h"
|
#include "celliterator.h"
|
||||||
#include "shellintegration.h"
|
|
||||||
|
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
#include <QSize>
|
#include <QSize>
|
||||||
@@ -12,9 +13,10 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace Terminal::Internal {
|
namespace TerminalSolution {
|
||||||
|
|
||||||
class Scrollback;
|
class Scrollback;
|
||||||
|
class SurfaceIntegration;
|
||||||
|
|
||||||
struct TerminalSurfacePrivate;
|
struct TerminalSurfacePrivate;
|
||||||
|
|
||||||
@@ -45,12 +47,12 @@ struct Cursor
|
|||||||
bool blink{false};
|
bool blink{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
class TerminalSurface : public QObject
|
class TERMINAL_EXPORT TerminalSurface : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT;
|
Q_OBJECT;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TerminalSurface(QSize initialGridSize, ShellIntegration *shellIntegration);
|
TerminalSurface(QSize initialGridSize);
|
||||||
~TerminalSurface();
|
~TerminalSurface();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -93,7 +95,8 @@ public:
|
|||||||
|
|
||||||
Cursor cursor() const;
|
Cursor cursor() const;
|
||||||
|
|
||||||
ShellIntegration *shellIntegration() const;
|
SurfaceIntegration *surfaceIntegration() const;
|
||||||
|
void setSurfaceIntegration(SurfaceIntegration *surfaceIntegration);
|
||||||
|
|
||||||
void mouseMove(QPoint pos, Qt::KeyboardModifiers modifiers);
|
void mouseMove(QPoint pos, Qt::KeyboardModifiers modifiers);
|
||||||
void mouseButton(Qt::MouseButton button, bool pressed, Qt::KeyboardModifiers modifiers);
|
void mouseButton(Qt::MouseButton button, bool pressed, Qt::KeyboardModifiers modifiers);
|
||||||
@@ -104,11 +107,9 @@ signals:
|
|||||||
void cursorChanged(Cursor oldCursor, Cursor newCursor);
|
void cursorChanged(Cursor oldCursor, Cursor newCursor);
|
||||||
void altscreenChanged(bool altScreen);
|
void altscreenChanged(bool altScreen);
|
||||||
void unscroll();
|
void unscroll();
|
||||||
void bell();
|
|
||||||
void titleChanged(const QString &title);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<TerminalSurfacePrivate> d;
|
std::unique_ptr<TerminalSurfacePrivate> d;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Terminal::Internal
|
} // namespace TerminalSolution
|
1263
src/libs/solutions/terminal/terminalview.cpp
Normal file
1263
src/libs/solutions/terminal/terminalview.cpp
Normal file
File diff suppressed because it is too large
Load Diff
221
src/libs/solutions/terminal/terminalview.h
Normal file
221
src/libs/solutions/terminal/terminalview.h
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "terminal_global.h"
|
||||||
|
#include "terminalsurface.h"
|
||||||
|
|
||||||
|
#include <QAbstractScrollArea>
|
||||||
|
#include <QAction>
|
||||||
|
#include <QTextLayout>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
namespace TerminalSolution {
|
||||||
|
|
||||||
|
class SurfaceIntegration;
|
||||||
|
class TerminalViewPrivate;
|
||||||
|
|
||||||
|
struct SearchHit
|
||||||
|
{
|
||||||
|
int start{-1};
|
||||||
|
int end{-1};
|
||||||
|
|
||||||
|
bool operator!=(const SearchHit &other) const
|
||||||
|
{
|
||||||
|
return start != other.start || end != other.end;
|
||||||
|
}
|
||||||
|
bool operator==(const SearchHit &other) const { return !operator!=(other); }
|
||||||
|
};
|
||||||
|
|
||||||
|
QString defaultFontFamily();
|
||||||
|
int defaultFontSize();
|
||||||
|
|
||||||
|
class TERMINAL_EXPORT TerminalView : public QAbstractScrollArea
|
||||||
|
{
|
||||||
|
friend class CellIterator;
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
enum class WidgetColorIdx {
|
||||||
|
Foreground = ColorIndex::Foreground,
|
||||||
|
Background = ColorIndex::Background,
|
||||||
|
Selection,
|
||||||
|
FindMatch,
|
||||||
|
};
|
||||||
|
|
||||||
|
TerminalView(QWidget *parent = nullptr);
|
||||||
|
~TerminalView() override;
|
||||||
|
|
||||||
|
void setAllowBlinkingCursor(bool allow);
|
||||||
|
bool allowBlinkingCursor() const;
|
||||||
|
|
||||||
|
void setFont(const QFont &font);
|
||||||
|
|
||||||
|
void copyToClipboard();
|
||||||
|
void pasteFromClipboard();
|
||||||
|
void copyLinkToClipboard();
|
||||||
|
|
||||||
|
struct Selection
|
||||||
|
{
|
||||||
|
int start;
|
||||||
|
int end;
|
||||||
|
bool final{false};
|
||||||
|
|
||||||
|
bool operator!=(const Selection &other) const
|
||||||
|
{
|
||||||
|
return start != other.start || end != other.end || final != other.final;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const Selection &other) const { return !operator!=(other); }
|
||||||
|
};
|
||||||
|
|
||||||
|
std::optional<Selection> selection() const;
|
||||||
|
void clearSelection();
|
||||||
|
|
||||||
|
void zoomIn();
|
||||||
|
void zoomOut();
|
||||||
|
|
||||||
|
void moveCursorWordLeft();
|
||||||
|
void moveCursorWordRight();
|
||||||
|
|
||||||
|
void clearContents();
|
||||||
|
|
||||||
|
void setSurfaceIntegration(SurfaceIntegration *surfaceIntegration);
|
||||||
|
void setColors(const std::array<QColor, 20> &colors);
|
||||||
|
|
||||||
|
struct Link
|
||||||
|
{
|
||||||
|
QString text;
|
||||||
|
int targetLine = 0;
|
||||||
|
int targetColumn = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LinkSelection : public Selection
|
||||||
|
{
|
||||||
|
Link link;
|
||||||
|
|
||||||
|
bool operator!=(const LinkSelection &other) const
|
||||||
|
{
|
||||||
|
return link.text != other.link.text || link.targetLine != other.link.targetLine
|
||||||
|
|| link.targetColumn != other.link.targetColumn || Selection::operator!=(other);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual void writeToPty(const QByteArray &data) { Q_UNUSED(data); }
|
||||||
|
void writeToTerminal(const QByteArray &data, bool forceFlush);
|
||||||
|
|
||||||
|
void restart();
|
||||||
|
|
||||||
|
virtual const QList<SearchHit> &searchHits() const
|
||||||
|
{
|
||||||
|
static QList<SearchHit> noHits;
|
||||||
|
return noHits;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void resizePty(QSize newSize) { Q_UNUSED(newSize); }
|
||||||
|
virtual void setClipboard(const QString &text) { Q_UNUSED(text); }
|
||||||
|
virtual std::optional<Link> toLink(const QString &text)
|
||||||
|
{
|
||||||
|
Q_UNUSED(text);
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void selectionChanged(const std::optional<Selection> &newSelection)
|
||||||
|
{
|
||||||
|
Q_UNUSED(newSelection);
|
||||||
|
}
|
||||||
|
virtual void linkActivated(const Link &link) { Q_UNUSED(link); }
|
||||||
|
virtual void contextMenuRequested(const QPoint &pos) { Q_UNUSED(pos); }
|
||||||
|
|
||||||
|
virtual void surfaceChanged(){};
|
||||||
|
|
||||||
|
TerminalSurface *surface() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintEvent(QPaintEvent *event) override;
|
||||||
|
void keyPressEvent(QKeyEvent *event) override;
|
||||||
|
void keyReleaseEvent(QKeyEvent *event) override;
|
||||||
|
void resizeEvent(QResizeEvent *event) override;
|
||||||
|
void wheelEvent(QWheelEvent *event) override;
|
||||||
|
void focusInEvent(QFocusEvent *event) override;
|
||||||
|
void focusOutEvent(QFocusEvent *event) override;
|
||||||
|
void inputMethodEvent(QInputMethodEvent *event) override;
|
||||||
|
|
||||||
|
void mousePressEvent(QMouseEvent *event) override;
|
||||||
|
void mouseMoveEvent(QMouseEvent *event) override;
|
||||||
|
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||||
|
void mouseDoubleClickEvent(QMouseEvent *event) override;
|
||||||
|
|
||||||
|
bool event(QEvent *event) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void setupSurface();
|
||||||
|
|
||||||
|
int paintCell(QPainter &p,
|
||||||
|
const QRectF &cellRect,
|
||||||
|
QPoint gridPos,
|
||||||
|
const TerminalCell &cell,
|
||||||
|
QFont &f,
|
||||||
|
QList<SearchHit>::const_iterator &searchIt) const;
|
||||||
|
void paintCells(QPainter &painter, QPaintEvent *event) const;
|
||||||
|
void paintCursor(QPainter &painter) const;
|
||||||
|
void paintPreedit(QPainter &painter) const;
|
||||||
|
bool paintFindMatches(QPainter &painter,
|
||||||
|
QList<SearchHit>::const_iterator &searchIt,
|
||||||
|
const QRectF &cellRect,
|
||||||
|
const QPoint gridPos) const;
|
||||||
|
|
||||||
|
bool paintSelection(QPainter &painter, const QRectF &cellRect, const QPoint gridPos) const;
|
||||||
|
void paintDebugSelection(QPainter &painter, const Selection &selection) const;
|
||||||
|
|
||||||
|
qreal topMargin() const;
|
||||||
|
|
||||||
|
QPoint viewportToGlobal(QPoint p) const;
|
||||||
|
QPoint globalToViewport(QPoint p) const;
|
||||||
|
QPoint globalToGrid(QPointF p) const;
|
||||||
|
QPointF gridToGlobal(QPoint p, bool bottom = false, bool right = false) const;
|
||||||
|
QRect gridToViewport(QRect rect) const;
|
||||||
|
QPoint toGridPos(QMouseEvent *event) const;
|
||||||
|
|
||||||
|
void updateViewport();
|
||||||
|
void updateViewportRect(const QRect &rect);
|
||||||
|
|
||||||
|
int textLineFromPixel(int y) const;
|
||||||
|
std::optional<int> textPosFromPoint(const QTextLayout &textLayout, QPoint p) const;
|
||||||
|
|
||||||
|
std::optional<QTextLayout::FormatRange> selectionToFormatRange(Selection selection,
|
||||||
|
const QTextLayout &layout,
|
||||||
|
int rowOffset) const;
|
||||||
|
|
||||||
|
bool checkLinkAt(const QPoint &pos);
|
||||||
|
|
||||||
|
struct TextAndOffsets
|
||||||
|
{
|
||||||
|
int start;
|
||||||
|
int end;
|
||||||
|
std::u32string text;
|
||||||
|
};
|
||||||
|
|
||||||
|
TextAndOffsets textAt(const QPoint &pos) const;
|
||||||
|
|
||||||
|
void applySizeChange();
|
||||||
|
void updateScrollBars();
|
||||||
|
|
||||||
|
void flushVTerm(bool force);
|
||||||
|
|
||||||
|
bool setSelection(const std::optional<Selection> &selection, bool scroll = true);
|
||||||
|
QString textFromSelection() const;
|
||||||
|
|
||||||
|
void configBlinkTimer();
|
||||||
|
|
||||||
|
QColor toQColor(std::variant<int, QColor> color) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<TerminalViewPrivate> d;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace TerminalSolution
|
@@ -1,12 +1,8 @@
|
|||||||
|
|
||||||
add_qtc_plugin(Terminal
|
add_qtc_plugin(Terminal
|
||||||
PLUGIN_DEPENDS Core ProjectExplorer
|
PLUGIN_DEPENDS Core ProjectExplorer
|
||||||
DEPENDS libvterm ptyqt
|
DEPENDS TerminalLib
|
||||||
SOURCES
|
SOURCES
|
||||||
celliterator.cpp celliterator.h
|
|
||||||
glyphcache.cpp glyphcache.h
|
|
||||||
keys.cpp keys.h
|
|
||||||
scrollback.cpp scrollback.h
|
|
||||||
shellintegration.cpp shellintegration.h
|
shellintegration.cpp shellintegration.h
|
||||||
shellmodel.cpp shellmodel.h
|
shellmodel.cpp shellmodel.h
|
||||||
shortcutmap.cpp shortcutmap.h
|
shortcutmap.cpp shortcutmap.h
|
||||||
@@ -18,7 +14,6 @@ add_qtc_plugin(Terminal
|
|||||||
terminalprocessimpl.cpp terminalprocessimpl.h
|
terminalprocessimpl.cpp terminalprocessimpl.h
|
||||||
terminalsearch.cpp terminalsearch.h
|
terminalsearch.cpp terminalsearch.h
|
||||||
terminalsettings.cpp terminalsettings.h
|
terminalsettings.cpp terminalsettings.h
|
||||||
terminalsurface.cpp terminalsurface.h
|
|
||||||
terminaltr.h
|
terminaltr.h
|
||||||
terminalwidget.cpp terminalwidget.h
|
terminalwidget.cpp terminalwidget.h
|
||||||
)
|
)
|
||||||
|
@@ -3,10 +3,13 @@
|
|||||||
|
|
||||||
#include "shellintegration.h"
|
#include "shellintegration.h"
|
||||||
|
|
||||||
|
#include "terminalsettings.h"
|
||||||
|
|
||||||
#include <utils/environment.h>
|
#include <utils/environment.h>
|
||||||
#include <utils/filepath.h>
|
#include <utils/filepath.h>
|
||||||
#include <utils/stringutils.h>
|
#include <utils/stringutils.h>
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
|
|
||||||
Q_LOGGING_CATEGORY(integrationLog, "qtc.terminal.shellintegration", QtWarningMsg)
|
Q_LOGGING_CATEGORY(integrationLog, "qtc.terminal.shellintegration", QtWarningMsg)
|
||||||
@@ -74,9 +77,12 @@ bool ShellIntegration::canIntegrate(const Utils::CommandLine &cmdLine)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShellIntegration::onOsc(int cmd, const VTermStringFragment &fragment)
|
void ShellIntegration::onOsc(int cmd, std::string_view str, bool initial, bool final)
|
||||||
{
|
{
|
||||||
QString d = QString::fromLocal8Bit(fragment.str, fragment.len);
|
Q_UNUSED(initial);
|
||||||
|
Q_UNUSED(final);
|
||||||
|
|
||||||
|
QString d = QString::fromLocal8Bit(str);
|
||||||
const auto [command, data] = Utils::splitAtFirst(d, ';');
|
const auto [command, data] = Utils::splitAtFirst(d, ';');
|
||||||
|
|
||||||
if (cmd == 1337) {
|
if (cmd == 1337) {
|
||||||
@@ -103,6 +109,17 @@ void ShellIntegration::onOsc(int cmd, const VTermStringFragment &fragment)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ShellIntegration::onBell()
|
||||||
|
{
|
||||||
|
if (settings().audibleBell.value())
|
||||||
|
QApplication::beep();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShellIntegration::onTitle(const QString &title)
|
||||||
|
{
|
||||||
|
emit titleChanged(title);
|
||||||
|
}
|
||||||
|
|
||||||
void ShellIntegration::prepareProcess(Utils::Process &process)
|
void ShellIntegration::prepareProcess(Utils::Process &process)
|
||||||
{
|
{
|
||||||
Environment env = process.environment().hasChanges() ? process.environment()
|
Environment env = process.environment().hasChanges() ? process.environment()
|
||||||
|
@@ -7,25 +7,28 @@
|
|||||||
#include <utils/commandline.h>
|
#include <utils/commandline.h>
|
||||||
#include <utils/process.h>
|
#include <utils/process.h>
|
||||||
|
|
||||||
#include <vterm.h>
|
#include <solutions/terminal/surfaceintegration.h>
|
||||||
|
|
||||||
#include <QTemporaryDir>
|
#include <QTemporaryDir>
|
||||||
|
|
||||||
namespace Terminal {
|
namespace Terminal {
|
||||||
|
|
||||||
class ShellIntegration : public QObject
|
class ShellIntegration : public QObject, public TerminalSolution::SurfaceIntegration
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
static bool canIntegrate(const Utils::CommandLine &cmdLine);
|
static bool canIntegrate(const Utils::CommandLine &cmdLine);
|
||||||
|
|
||||||
void onOsc(int cmd, const VTermStringFragment &fragment);
|
void onOsc(int cmd, std::string_view str, bool initial, bool final) override;
|
||||||
|
void onBell() override;
|
||||||
|
void onTitle(const QString &title) override;
|
||||||
|
|
||||||
void prepareProcess(Utils::Process &process);
|
void prepareProcess(Utils::Process &process);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void commandChanged(const Utils::CommandLine &command);
|
void commandChanged(const Utils::CommandLine &command);
|
||||||
void currentDirChanged(const QString &dir);
|
void currentDirChanged(const QString &dir);
|
||||||
|
void titleChanged(const QString &title);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QTemporaryDir m_tempDir;
|
QTemporaryDir m_tempDir;
|
||||||
|
@@ -80,7 +80,8 @@ TerminalPane::TerminalPane(QObject *parent)
|
|||||||
m_escSettingButton->setToolTip(Tr::tr("Sends Esc to terminal instead of Qt Creator."));
|
m_escSettingButton->setToolTip(Tr::tr("Sends Esc to terminal instead of Qt Creator."));
|
||||||
} else {
|
} else {
|
||||||
m_escSettingButton->setText(shiftEsc);
|
m_escSettingButton->setText(shiftEsc);
|
||||||
m_escSettingButton->setToolTip(Tr::tr("Press %1 to send Esc to terminal.").arg(shiftEsc));
|
m_escSettingButton->setToolTip(
|
||||||
|
Tr::tr("Press %1 to send Esc to terminal.").arg(shiftEsc));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -17,17 +17,18 @@ using namespace std::chrono_literals;
|
|||||||
|
|
||||||
namespace Terminal {
|
namespace Terminal {
|
||||||
|
|
||||||
using namespace Terminal::Internal;
|
|
||||||
|
|
||||||
constexpr std::chrono::milliseconds debounceInterval = 100ms;
|
constexpr std::chrono::milliseconds debounceInterval = 100ms;
|
||||||
|
|
||||||
TerminalSearch::TerminalSearch(TerminalSurface *surface)
|
TerminalSearch::TerminalSearch(TerminalSolution::TerminalSurface *surface)
|
||||||
: m_surface(surface)
|
: m_surface(surface)
|
||||||
{
|
{
|
||||||
m_debounceTimer.setInterval(debounceInterval);
|
m_debounceTimer.setInterval(debounceInterval);
|
||||||
m_debounceTimer.setSingleShot(true);
|
m_debounceTimer.setSingleShot(true);
|
||||||
|
|
||||||
connect(surface, &TerminalSurface::invalidated, this, &TerminalSearch::updateHits);
|
connect(surface,
|
||||||
|
&TerminalSolution::TerminalSurface::invalidated,
|
||||||
|
this,
|
||||||
|
&TerminalSearch::updateHits);
|
||||||
connect(&m_debounceTimer, &QTimer::timeout, this, &TerminalSearch::debouncedUpdateHits);
|
connect(&m_debounceTimer, &QTimer::timeout, this, &TerminalSearch::debouncedUpdateHits);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,9 +86,9 @@ bool isSpace(char32_t a, char32_t b)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<SearchHit> TerminalSearch::search()
|
QList<TerminalSolution::SearchHit> TerminalSearch::search()
|
||||||
{
|
{
|
||||||
QList<SearchHit> hits;
|
QList<TerminalSolution::SearchHit> hits;
|
||||||
|
|
||||||
std::function<bool(char32_t, char32_t)> compare;
|
std::function<bool(char32_t, char32_t)> compare;
|
||||||
|
|
||||||
@@ -108,12 +109,12 @@ QList<SearchHit> TerminalSearch::search()
|
|||||||
searchString.insert(searchString.begin(), std::numeric_limits<char32_t>::max());
|
searchString.insert(searchString.begin(), std::numeric_limits<char32_t>::max());
|
||||||
}
|
}
|
||||||
|
|
||||||
Internal::CellIterator it = m_surface->begin();
|
TerminalSolution::CellIterator it = m_surface->begin();
|
||||||
while (it != m_surface->end()) {
|
while (it != m_surface->end()) {
|
||||||
it = std::search(it, m_surface->end(), searchString.begin(), searchString.end(), compare);
|
it = std::search(it, m_surface->end(), searchString.begin(), searchString.end(), compare);
|
||||||
|
|
||||||
if (it != m_surface->end()) {
|
if (it != m_surface->end()) {
|
||||||
auto hit = SearchHit{it.position(),
|
auto hit = TerminalSolution::SearchHit{it.position(),
|
||||||
static_cast<int>(it.position() + searchString.size())};
|
static_cast<int>(it.position() + searchString.size())};
|
||||||
if (m_findFlags.testFlag(FindFlag::FindWholeWords)) {
|
if (m_findFlags.testFlag(FindFlag::FindWholeWords)) {
|
||||||
hit.start++;
|
hit.start++;
|
||||||
@@ -127,9 +128,9 @@ QList<SearchHit> TerminalSearch::search()
|
|||||||
return hits;
|
return hits;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<SearchHit> TerminalSearch::searchRegex()
|
QList<TerminalSolution::SearchHit> TerminalSearch::searchRegex()
|
||||||
{
|
{
|
||||||
QList<SearchHit> hits;
|
QList<TerminalSolution::SearchHit> hits;
|
||||||
|
|
||||||
QString allText;
|
QString allText;
|
||||||
allText.reserve(1000);
|
allText.reserve(1000);
|
||||||
@@ -170,7 +171,7 @@ QList<SearchHit> TerminalSearch::searchRegex()
|
|||||||
}
|
}
|
||||||
e -= adjust;
|
e -= adjust;
|
||||||
}
|
}
|
||||||
hits << SearchHit{s, e};
|
hits << TerminalSolution::SearchHit{s, e};
|
||||||
}
|
}
|
||||||
|
|
||||||
return hits;
|
return hits;
|
||||||
@@ -185,7 +186,7 @@ void TerminalSearch::debouncedUpdateHits()
|
|||||||
|
|
||||||
const bool regex = m_findFlags.testFlag(FindFlag::FindRegularExpression);
|
const bool regex = m_findFlags.testFlag(FindFlag::FindRegularExpression);
|
||||||
|
|
||||||
QList<SearchHit> hits = regex ? searchRegex() : search();
|
QList<TerminalSolution::SearchHit> hits = regex ? searchRegex() : search();
|
||||||
|
|
||||||
if (hits != m_hits) {
|
if (hits != m_hits) {
|
||||||
m_currentHit = -1;
|
m_currentHit = -1;
|
||||||
|
@@ -3,7 +3,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "terminalsurface.h"
|
#include <terminal/terminalsurface.h>
|
||||||
|
|
||||||
|
#include <solutions/terminal/terminalview.h>
|
||||||
|
|
||||||
#include <coreplugin/find/ifindsupport.h>
|
#include <coreplugin/find/ifindsupport.h>
|
||||||
#include <coreplugin/find/textfindconstants.h>
|
#include <coreplugin/find/textfindconstants.h>
|
||||||
@@ -12,19 +14,7 @@
|
|||||||
|
|
||||||
namespace Terminal {
|
namespace Terminal {
|
||||||
|
|
||||||
struct SearchHit
|
struct SearchHitWithText : TerminalSolution::SearchHit
|
||||||
{
|
|
||||||
int start{-1};
|
|
||||||
int end{-1};
|
|
||||||
|
|
||||||
bool operator!=(const SearchHit &other) const
|
|
||||||
{
|
|
||||||
return start != other.start || end != other.end;
|
|
||||||
}
|
|
||||||
bool operator==(const SearchHit &other) const { return !operator!=(other); }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SearchHitWithText : SearchHit
|
|
||||||
{
|
{
|
||||||
QString text;
|
QString text;
|
||||||
};
|
};
|
||||||
@@ -33,17 +23,17 @@ class TerminalSearch : public Core::IFindSupport
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
TerminalSearch(Internal::TerminalSurface *surface);
|
TerminalSearch(TerminalSolution::TerminalSurface *surface);
|
||||||
|
|
||||||
void setCurrentSelection(std::optional<SearchHitWithText> selection);
|
void setCurrentSelection(std::optional<SearchHitWithText> selection);
|
||||||
void setSearchString(const QString &searchString, Utils::FindFlags findFlags);
|
void setSearchString(const QString &searchString, Utils::FindFlags findFlags);
|
||||||
void nextHit();
|
void nextHit();
|
||||||
void previousHit();
|
void previousHit();
|
||||||
|
|
||||||
const QList<SearchHit> &hits() const { return m_hits; }
|
const QList<TerminalSolution::SearchHit> &hits() const { return m_hits; }
|
||||||
SearchHit currentHit() const
|
TerminalSolution::SearchHit currentHit() const
|
||||||
{
|
{
|
||||||
return m_currentHit >= 0 ? m_hits.at(m_currentHit) : SearchHit{};
|
return m_currentHit >= 0 ? m_hits.at(m_currentHit) : TerminalSolution::SearchHit{};
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -65,17 +55,17 @@ signals:
|
|||||||
protected:
|
protected:
|
||||||
void updateHits();
|
void updateHits();
|
||||||
void debouncedUpdateHits();
|
void debouncedUpdateHits();
|
||||||
QList<SearchHit> search();
|
QList<TerminalSolution::SearchHit> search();
|
||||||
QList<SearchHit> searchRegex();
|
QList<TerminalSolution::SearchHit> searchRegex();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::optional<SearchHitWithText> m_currentSelection;
|
std::optional<SearchHitWithText> m_currentSelection;
|
||||||
QString m_currentSearchString;
|
QString m_currentSearchString;
|
||||||
Utils::FindFlags m_findFlags;
|
Utils::FindFlags m_findFlags;
|
||||||
Internal::TerminalSurface *m_surface;
|
TerminalSolution::TerminalSurface *m_surface;
|
||||||
|
|
||||||
int m_currentHit{-1};
|
int m_currentHit{-1};
|
||||||
QList<SearchHit> m_hits;
|
QList<TerminalSolution::SearchHit> m_hits;
|
||||||
QTimer m_debounceTimer;
|
QTimer m_debounceTimer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -8,8 +8,6 @@
|
|||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
#include <coreplugin/dialogs/ioptionspage.h>
|
#include <coreplugin/dialogs/ioptionspage.h>
|
||||||
|
|
||||||
#include <libptyqt/ptyqt.h>
|
|
||||||
|
|
||||||
#include <utils/dropsupport.h>
|
#include <utils/dropsupport.h>
|
||||||
#include <utils/environment.h>
|
#include <utils/environment.h>
|
||||||
#include <utils/expected.h>
|
#include <utils/expected.h>
|
||||||
@@ -72,7 +70,6 @@ void setupColor(TerminalSettings *settings,
|
|||||||
color.setSettingsKey(label);
|
color.setSettingsKey(label);
|
||||||
color.setDefaultValue(defaultColor);
|
color.setDefaultValue(defaultColor);
|
||||||
color.setToolTip(Tr::tr("The color used for %1.").arg(label));
|
color.setToolTip(Tr::tr("The color used for %1.").arg(label));
|
||||||
|
|
||||||
settings->registerAspect(&color);
|
settings->registerAspect(&color);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -479,7 +476,7 @@ TerminalSettings::TerminalSettings()
|
|||||||
fontComboBox->setCurrentFont(font());
|
fontComboBox->setCurrentFont(font());
|
||||||
|
|
||||||
connect(fontComboBox, &QFontComboBox::currentFontChanged, this, [this](const QFont &f) {
|
connect(fontComboBox, &QFontComboBox::currentFontChanged, this, [this](const QFont &f) {
|
||||||
font.setValue(f.family());
|
font.setVolatileValue(f.family());
|
||||||
});
|
});
|
||||||
|
|
||||||
auto loadThemeButton = new QPushButton(Tr::tr("Load Theme..."));
|
auto loadThemeButton = new QPushButton(Tr::tr("Load Theme..."));
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -3,83 +3,36 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "shellintegration.h"
|
||||||
#include "shortcutmap.h"
|
#include "shortcutmap.h"
|
||||||
#include "terminalsearch.h"
|
#include "terminalsearch.h"
|
||||||
#include "terminalsurface.h"
|
|
||||||
|
#include <solutions/terminal/terminalview.h>
|
||||||
|
|
||||||
#include <aggregation/aggregate.h>
|
#include <aggregation/aggregate.h>
|
||||||
|
|
||||||
#include <coreplugin/icontext.h>
|
|
||||||
#include <coreplugin/actionmanager/command.h>
|
#include <coreplugin/actionmanager/command.h>
|
||||||
|
#include <coreplugin/icontext.h>
|
||||||
|
|
||||||
#include <utils/link.h>
|
#include <utils/link.h>
|
||||||
#include <utils/process.h>
|
#include <utils/process.h>
|
||||||
#include <utils/terminalhooks.h>
|
#include <utils/terminalhooks.h>
|
||||||
|
|
||||||
#include <QAbstractScrollArea>
|
|
||||||
#include <QAction>
|
|
||||||
#include <QTextLayout>
|
|
||||||
#include <QTimer>
|
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace Terminal {
|
namespace Terminal {
|
||||||
|
|
||||||
using RegisteredAction = std::unique_ptr<QAction, std::function<void(QAction *)>>;
|
using RegisteredAction = std::unique_ptr<QAction, std::function<void(QAction *)>>;
|
||||||
|
|
||||||
class TerminalWidget : public QAbstractScrollArea
|
class TerminalWidget : public TerminalSolution::TerminalView
|
||||||
{
|
{
|
||||||
friend class CellIterator;
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
TerminalWidget(QWidget *parent = nullptr,
|
TerminalWidget(QWidget *parent = nullptr,
|
||||||
const Utils::Terminal::OpenTerminalParameters &openParameters = {});
|
const Utils::Terminal::OpenTerminalParameters &openParameters = {});
|
||||||
|
|
||||||
void setFont(const QFont &font);
|
|
||||||
|
|
||||||
void copyToClipboard();
|
|
||||||
void pasteFromClipboard();
|
|
||||||
void copyLinkToClipboard();
|
|
||||||
|
|
||||||
void clearSelection();
|
|
||||||
|
|
||||||
void zoomIn();
|
|
||||||
void zoomOut();
|
|
||||||
|
|
||||||
void moveCursorWordLeft();
|
|
||||||
void moveCursorWordRight();
|
|
||||||
|
|
||||||
void clearContents();
|
|
||||||
|
|
||||||
void closeTerminal();
|
void closeTerminal();
|
||||||
|
|
||||||
TerminalSearch *search() { return m_search.get(); }
|
TerminalSearch *search() { return m_search.get(); }
|
||||||
|
|
||||||
struct Selection
|
|
||||||
{
|
|
||||||
int start;
|
|
||||||
int end;
|
|
||||||
bool final{false};
|
|
||||||
|
|
||||||
bool operator!=(const Selection &other) const
|
|
||||||
{
|
|
||||||
return start != other.start || end != other.end || final != other.final;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(const Selection &other) const { return !operator!=(other); }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct LinkSelection : public Selection
|
|
||||||
{
|
|
||||||
Utils::Link link;
|
|
||||||
|
|
||||||
bool operator!=(const LinkSelection &other) const
|
|
||||||
{
|
|
||||||
return link != other.link || Selection::operator!=(other);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void setShellName(const QString &shellName);
|
void setShellName(const QString &shellName);
|
||||||
QString shellName() const;
|
QString shellName() const;
|
||||||
QString title() const;
|
QString title() const;
|
||||||
@@ -102,142 +55,52 @@ signals:
|
|||||||
void titleChanged();
|
void titleChanged();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void paintEvent(QPaintEvent *event) override;
|
|
||||||
void keyPressEvent(QKeyEvent *event) override;
|
|
||||||
void keyReleaseEvent(QKeyEvent *event) override;
|
|
||||||
void resizeEvent(QResizeEvent *event) override;
|
|
||||||
void wheelEvent(QWheelEvent *event) override;
|
|
||||||
void focusInEvent(QFocusEvent *event) override;
|
|
||||||
void focusOutEvent(QFocusEvent *event) override;
|
|
||||||
void inputMethodEvent(QInputMethodEvent *event) override;
|
|
||||||
|
|
||||||
void mousePressEvent(QMouseEvent *event) override;
|
|
||||||
void mouseMoveEvent(QMouseEvent *event) override;
|
|
||||||
void mouseReleaseEvent(QMouseEvent *event) override;
|
|
||||||
void mouseDoubleClickEvent(QMouseEvent *event) override;
|
|
||||||
|
|
||||||
void dragEnterEvent(QDragEnterEvent *event) override;
|
void dragEnterEvent(QDragEnterEvent *event) override;
|
||||||
void dropEvent(QDropEvent *event) override;
|
void dropEvent(QDropEvent *event) override;
|
||||||
|
|
||||||
void showEvent(QShowEvent *event) override;
|
void showEvent(QShowEvent *event) override;
|
||||||
|
void focusInEvent(QFocusEvent *event) override;
|
||||||
bool event(QEvent *event) override;
|
bool event(QEvent *event) override;
|
||||||
|
|
||||||
protected:
|
|
||||||
void onReadyRead(bool forceFlush);
|
void onReadyRead(bool forceFlush);
|
||||||
void setupSurface();
|
|
||||||
void setupFont();
|
void setupFont();
|
||||||
void setupPty();
|
void setupPty();
|
||||||
void setupColors();
|
void setupColors();
|
||||||
void setupActions();
|
void setupActions();
|
||||||
|
|
||||||
void writeToPty(const QByteArray &data);
|
void handleEscKey(QKeyEvent *event);
|
||||||
|
|
||||||
int paintCell(QPainter &p,
|
void surfaceChanged() override;
|
||||||
const QRectF &cellRect,
|
|
||||||
QPoint gridPos,
|
|
||||||
const Internal::TerminalCell &cell,
|
|
||||||
QFont &f,
|
|
||||||
QList<SearchHit>::const_iterator &searchIt) const;
|
|
||||||
void paintCells(QPainter &painter, QPaintEvent *event) const;
|
|
||||||
void paintCursor(QPainter &painter) const;
|
|
||||||
void paintPreedit(QPainter &painter) const;
|
|
||||||
bool paintFindMatches(QPainter &painter,
|
|
||||||
QList<SearchHit>::const_iterator &searchIt,
|
|
||||||
const QRectF &cellRect,
|
|
||||||
const QPoint gridPos) const;
|
|
||||||
bool paintSelection(QPainter &painter, const QRectF &cellRect, const QPoint gridPos) const;
|
|
||||||
void paintDebugSelection(QPainter &painter, const Selection &selection) const;
|
|
||||||
|
|
||||||
qreal topMargin() const;
|
void selectionChanged(const std::optional<Selection> &newSelection) override;
|
||||||
|
void linkActivated(const Link &link) override;
|
||||||
|
void contextMenuRequested(const QPoint &pos) override;
|
||||||
|
|
||||||
QPoint viewportToGlobal(QPoint p) const;
|
void writeToPty(const QByteArray &data) override;
|
||||||
QPoint globalToViewport(QPoint p) const;
|
void resizePty(QSize newSize) override;
|
||||||
QPoint globalToGrid(QPointF p) const;
|
void setClipboard(const QString &text) override;
|
||||||
QPointF gridToGlobal(QPoint p, bool bottom = false, bool right = false) const;
|
std::optional<TerminalView::Link> toLink(const QString &text) override;
|
||||||
QRect gridToViewport(QRect rect) const;
|
|
||||||
QPoint toGridPos(QMouseEvent *event) const;
|
|
||||||
|
|
||||||
void updateViewport();
|
const QList<TerminalSolution::SearchHit> &searchHits() const override;
|
||||||
void updateViewportRect(const QRect &rect);
|
|
||||||
|
|
||||||
int textLineFromPixel(int y) const;
|
|
||||||
std::optional<int> textPosFromPoint(const QTextLayout &textLayout, QPoint p) const;
|
|
||||||
|
|
||||||
std::optional<QTextLayout::FormatRange> selectionToFormatRange(
|
|
||||||
TerminalWidget::Selection selection, const QTextLayout &layout, int rowOffset) const;
|
|
||||||
|
|
||||||
bool checkLinkAt(const QPoint &pos);
|
|
||||||
|
|
||||||
struct TextAndOffsets
|
|
||||||
{
|
|
||||||
int start;
|
|
||||||
int end;
|
|
||||||
std::u32string text;
|
|
||||||
};
|
|
||||||
|
|
||||||
TextAndOffsets textAt(const QPoint &pos) const;
|
|
||||||
|
|
||||||
void applySizeChange();
|
|
||||||
void updateScrollBars();
|
|
||||||
|
|
||||||
void flushVTerm(bool force);
|
|
||||||
|
|
||||||
bool setSelection(const std::optional<Selection> &selection, bool scroll = true);
|
|
||||||
QString textFromSelection() const;
|
|
||||||
|
|
||||||
void configBlinkTimer();
|
|
||||||
|
|
||||||
QColor toQColor(std::variant<int, QColor> color) const;
|
|
||||||
|
|
||||||
void updateCopyState();
|
|
||||||
|
|
||||||
RegisteredAction registerAction(Utils::Id commandId, const Core::Context &context);
|
RegisteredAction registerAction(Utils::Id commandId, const Core::Context &context);
|
||||||
void registerShortcut(Core::Command *command);
|
void registerShortcut(Core::Command *command);
|
||||||
|
|
||||||
|
void updateCopyState();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Core::Context m_context;
|
Core::Context m_context;
|
||||||
std::unique_ptr<Utils::Process> m_process;
|
std::unique_ptr<Utils::Process> m_process;
|
||||||
std::unique_ptr<Internal::TerminalSurface> m_surface;
|
|
||||||
std::unique_ptr<ShellIntegration> m_shellIntegration;
|
std::unique_ptr<ShellIntegration> m_shellIntegration;
|
||||||
|
|
||||||
QString m_shellName;
|
QString m_shellName;
|
||||||
Utils::Id m_identifier;
|
|
||||||
|
|
||||||
QFont m_font;
|
|
||||||
QSizeF m_cellSize;
|
|
||||||
|
|
||||||
bool m_ignoreScroll{false};
|
|
||||||
|
|
||||||
QString m_preEditString;
|
|
||||||
QString m_title;
|
QString m_title;
|
||||||
|
|
||||||
std::optional<Selection> m_selection;
|
TerminalSolution::SearchHit m_lastSelectedHit{};
|
||||||
std::optional<LinkSelection> m_linkSelection;
|
|
||||||
|
|
||||||
struct
|
Utils::Id m_identifier;
|
||||||
{
|
|
||||||
QPoint start;
|
|
||||||
QPoint end;
|
|
||||||
} m_activeMouseSelect;
|
|
||||||
|
|
||||||
QTimer m_flushDelayTimer;
|
|
||||||
|
|
||||||
QTimer m_scrollTimer;
|
|
||||||
int m_scrollDirection{0};
|
|
||||||
|
|
||||||
std::array<QColor, 20> m_currentColors;
|
|
||||||
|
|
||||||
Utils::Terminal::OpenTerminalParameters m_openParameters;
|
Utils::Terminal::OpenTerminalParameters m_openParameters;
|
||||||
|
|
||||||
std::chrono::system_clock::time_point m_lastFlush;
|
|
||||||
std::chrono::system_clock::time_point m_lastDoubleClick;
|
|
||||||
bool m_selectLineMode{false};
|
|
||||||
|
|
||||||
Internal::Cursor m_cursor;
|
|
||||||
QTimer m_cursorBlinkTimer;
|
|
||||||
bool m_cursorBlinkState{true};
|
|
||||||
|
|
||||||
Utils::FilePath m_cwd;
|
Utils::FilePath m_cwd;
|
||||||
Utils::CommandLine m_currentCommand;
|
Utils::CommandLine m_currentCommand;
|
||||||
|
|
||||||
@@ -245,7 +108,6 @@ private:
|
|||||||
TerminalSearchPtr m_search;
|
TerminalSearchPtr m_search;
|
||||||
|
|
||||||
Aggregation::Aggregate *m_aggregate{nullptr};
|
Aggregation::Aggregate *m_aggregate{nullptr};
|
||||||
SearchHit m_lastSelectedHit{};
|
|
||||||
|
|
||||||
RegisteredAction m_copy;
|
RegisteredAction m_copy;
|
||||||
RegisteredAction m_paste;
|
RegisteredAction m_paste;
|
||||||
|
67
src/plugins/terminal/tests/mouse
Executable file
67
src/plugins/terminal/tests/mouse
Executable file
@@ -0,0 +1,67 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
|
||||||
|
function cleanup {
|
||||||
|
stty -echo
|
||||||
|
printf "\e[?1006;1000l"
|
||||||
|
}
|
||||||
|
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
stty -echo
|
||||||
|
|
||||||
|
# Enable SGR protocol and button press and release events
|
||||||
|
printf "\e[?1006;1000h"
|
||||||
|
|
||||||
|
while read -n 1 line
|
||||||
|
do
|
||||||
|
printf -v ch "%d" \'$line
|
||||||
|
if [ "27" != "$ch" ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
read -n 1 line
|
||||||
|
if [ "[" != "$line" ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
read -n 1 line
|
||||||
|
if [ "<" != "$line" ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
# Read button state
|
||||||
|
modifier=
|
||||||
|
while read -n 1 line
|
||||||
|
do
|
||||||
|
if [ ";" = "$line" ]; then
|
||||||
|
# End
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
printf -v modifier "$modifier$line"
|
||||||
|
done
|
||||||
|
# Read column
|
||||||
|
col=
|
||||||
|
while read -n 1 line
|
||||||
|
do
|
||||||
|
if [ ";" = "$line" ]; then
|
||||||
|
# End
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
printf -v col "$col$line"
|
||||||
|
done
|
||||||
|
# Read row
|
||||||
|
row=
|
||||||
|
while read -n 1 line
|
||||||
|
do
|
||||||
|
if [ "M" = "$line" ] || [ "m" = "$line" ]; then
|
||||||
|
# End
|
||||||
|
btn=$line
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
printf -v row "$row$line"
|
||||||
|
done
|
||||||
|
if [ "M" = "$btn" ]; then
|
||||||
|
echo "You pressed at $col x $row (mods: $modifier)"
|
||||||
|
else
|
||||||
|
echo "You released at $col x $row (mods: $modifier)"
|
||||||
|
fi
|
||||||
|
done < "${1:-/dev/stdin}"
|
||||||
|
|
Reference in New Issue
Block a user