forked from qt-creator/qt-creator
Terminal: Add search
* Adds new search widget to terminal * Adds new theme color "TerminalFindMatch" * Fixes ESC key handling in terminal Fixes: QTCREATORBUG-28946 Change-Id: I7b6057d13902a94a6bcd41dde6cc8ba8418cd585 Reviewed-by: Cristian Adam <cristian.adam@qt.io>
This commit is contained in:
@@ -387,6 +387,7 @@ QmlDesigner_ScrollBarHandleColor=ff505050
|
|||||||
TerminalForeground=ffffffff
|
TerminalForeground=ffffffff
|
||||||
TerminalBackground=ff000000
|
TerminalBackground=ff000000
|
||||||
TerminalSelection=7fffffff
|
TerminalSelection=7fffffff
|
||||||
|
TerminalFindMatch=7fffff00
|
||||||
TerminalAnsi0=000000
|
TerminalAnsi0=000000
|
||||||
TerminalAnsi1=8b1b10
|
TerminalAnsi1=8b1b10
|
||||||
TerminalAnsi2=4aa32e
|
TerminalAnsi2=4aa32e
|
||||||
|
|||||||
@@ -355,6 +355,7 @@ QmlDesigner_ScrollBarHandleColor=ff7a7a7a
|
|||||||
TerminalForeground=ff000000
|
TerminalForeground=ff000000
|
||||||
TerminalBackground=ffffffff
|
TerminalBackground=ffffffff
|
||||||
TerminalSelection=3f000000
|
TerminalSelection=3f000000
|
||||||
|
TerminalFindMatch=7fffff00
|
||||||
TerminalAnsi0=000000
|
TerminalAnsi0=000000
|
||||||
TerminalAnsi1=8b1b10
|
TerminalAnsi1=8b1b10
|
||||||
TerminalAnsi2=4aa32e
|
TerminalAnsi2=4aa32e
|
||||||
|
|||||||
@@ -399,6 +399,7 @@ PaletteTextDisabled=textDisabled
|
|||||||
TerminalForeground=ff000000
|
TerminalForeground=ff000000
|
||||||
TerminalBackground=ffffffff
|
TerminalBackground=ffffffff
|
||||||
TerminalSelection=3f000000
|
TerminalSelection=3f000000
|
||||||
|
TerminalFindMatch=7fffff00
|
||||||
TerminalAnsi0=000000
|
TerminalAnsi0=000000
|
||||||
TerminalAnsi1=8b1b10
|
TerminalAnsi1=8b1b10
|
||||||
TerminalAnsi2=4aa32e
|
TerminalAnsi2=4aa32e
|
||||||
|
|||||||
@@ -499,6 +499,7 @@ PalettePlaceholderText=ff808081
|
|||||||
TerminalForeground=ffffffff
|
TerminalForeground=ffffffff
|
||||||
TerminalBackground=ff000000
|
TerminalBackground=ff000000
|
||||||
TerminalSelection=7fffffff
|
TerminalSelection=7fffffff
|
||||||
|
TerminalFindMatch=7fffff00
|
||||||
TerminalAnsi0=000000
|
TerminalAnsi0=000000
|
||||||
TerminalAnsi1=8b1b10
|
TerminalAnsi1=8b1b10
|
||||||
TerminalAnsi2=4aa32e
|
TerminalAnsi2=4aa32e
|
||||||
|
|||||||
@@ -391,6 +391,7 @@ PalettePlaceholderText=ff7f7f80
|
|||||||
TerminalForeground=ffffffff
|
TerminalForeground=ffffffff
|
||||||
TerminalBackground=ff000000
|
TerminalBackground=ff000000
|
||||||
TerminalSelection=7fffffff
|
TerminalSelection=7fffffff
|
||||||
|
TerminalFindMatch=7fffff00
|
||||||
TerminalAnsi0=000000
|
TerminalAnsi0=000000
|
||||||
TerminalAnsi1=8b1b10
|
TerminalAnsi1=8b1b10
|
||||||
TerminalAnsi2=4aa32e
|
TerminalAnsi2=4aa32e
|
||||||
|
|||||||
@@ -364,6 +364,7 @@ QmlDesigner_ScrollBarHandleColor=ffcccccc
|
|||||||
TerminalForeground=ff000000
|
TerminalForeground=ff000000
|
||||||
TerminalBackground=ffffffff
|
TerminalBackground=ffffffff
|
||||||
TerminalSelection=3f000000
|
TerminalSelection=3f000000
|
||||||
|
TerminalFindMatch=7fffff00
|
||||||
TerminalAnsi0=000000
|
TerminalAnsi0=000000
|
||||||
TerminalAnsi1=8b1b10
|
TerminalAnsi1=8b1b10
|
||||||
TerminalAnsi2=4aa32e
|
TerminalAnsi2=4aa32e
|
||||||
|
|||||||
@@ -362,6 +362,7 @@ QmlDesigner_ScrollBarHandleColor=ff595b5c
|
|||||||
TerminalForeground=ff000000
|
TerminalForeground=ff000000
|
||||||
TerminalBackground=ffffffff
|
TerminalBackground=ffffffff
|
||||||
TerminalSelection=3f000000
|
TerminalSelection=3f000000
|
||||||
|
TerminalFindMatch=7fffff00
|
||||||
TerminalAnsi0=000000
|
TerminalAnsi0=000000
|
||||||
TerminalAnsi1=8b1b10
|
TerminalAnsi1=8b1b10
|
||||||
TerminalAnsi2=4aa32e
|
TerminalAnsi2=4aa32e
|
||||||
|
|||||||
@@ -423,6 +423,7 @@ public:
|
|||||||
TerminalForeground,
|
TerminalForeground,
|
||||||
TerminalBackground,
|
TerminalBackground,
|
||||||
TerminalSelection,
|
TerminalSelection,
|
||||||
|
TerminalFindMatch,
|
||||||
|
|
||||||
TerminalAnsi0,
|
TerminalAnsi0,
|
||||||
TerminalAnsi1,
|
TerminalAnsi1,
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ add_qtc_plugin(Terminal
|
|||||||
terminalpane.cpp terminalpane.h
|
terminalpane.cpp terminalpane.h
|
||||||
terminalplugin.cpp terminalplugin.h
|
terminalplugin.cpp terminalplugin.h
|
||||||
terminalprocessimpl.cpp terminalprocessimpl.h
|
terminalprocessimpl.cpp terminalprocessimpl.h
|
||||||
|
terminalsearch.cpp terminalsearch.h
|
||||||
terminalsettings.cpp terminalsettings.h
|
terminalsettings.cpp terminalsettings.h
|
||||||
terminalsettingspage.cpp terminalsettingspage.h
|
terminalsettingspage.cpp terminalsettingspage.h
|
||||||
terminalsurface.cpp terminalsurface.h
|
terminalsurface.cpp terminalsurface.h
|
||||||
|
|||||||
@@ -48,10 +48,11 @@ QPoint CellIterator::gridPos() const
|
|||||||
return m_surface->posToGrid(m_pos);
|
return m_surface->posToGrid(m_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CellIterator::updateChar()
|
bool CellIterator::updateChar()
|
||||||
{
|
{
|
||||||
QPoint cell = m_surface->posToGrid(m_pos);
|
QPoint cell = m_surface->posToGrid(m_pos);
|
||||||
m_char = m_surface->fetchCharAt(cell.x(), cell.y());
|
m_char = m_surface->fetchCharAt(cell.x(), cell.y());
|
||||||
|
return m_char != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
CellIterator &CellIterator::operator-=(int n)
|
CellIterator &CellIterator::operator-=(int n)
|
||||||
@@ -63,7 +64,9 @@ CellIterator &CellIterator::operator-=(int n)
|
|||||||
throw new std::runtime_error("-= n too big!");
|
throw new std::runtime_error("-= n too big!");
|
||||||
|
|
||||||
m_pos -= n;
|
m_pos -= n;
|
||||||
updateChar();
|
|
||||||
|
while (!updateChar() && m_pos > 0 && m_skipZeros)
|
||||||
|
m_pos--;
|
||||||
|
|
||||||
m_state = State::INSIDE;
|
m_state = State::INSIDE;
|
||||||
|
|
||||||
@@ -79,10 +82,14 @@ CellIterator &CellIterator::operator+=(int n)
|
|||||||
if (n == 0)
|
if (n == 0)
|
||||||
return *this;
|
return *this;
|
||||||
|
|
||||||
if (m_pos + n < m_maxpos) {
|
if (m_pos + n < m_maxpos + 1) {
|
||||||
m_state = State::INSIDE;
|
m_state = State::INSIDE;
|
||||||
m_pos += n;
|
m_pos += n;
|
||||||
updateChar();
|
while (!updateChar() && m_pos < (m_maxpos + 1) && m_skipZeros)
|
||||||
|
m_pos++;
|
||||||
|
|
||||||
|
if (m_pos == m_maxpos + 1)
|
||||||
|
m_state = State::END;
|
||||||
} else {
|
} else {
|
||||||
*this = m_surface->end();
|
*this = m_surface->end();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,13 +82,15 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
int position() const { return m_pos; }
|
int position() const { return m_pos; }
|
||||||
|
void setSkipZeros(bool skipZeros) { m_skipZeros = skipZeros; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateChar();
|
bool updateChar();
|
||||||
|
|
||||||
const TerminalSurface *m_surface{nullptr};
|
const TerminalSurface *m_surface{nullptr};
|
||||||
int m_pos{-1};
|
int m_pos{-1};
|
||||||
int m_maxpos{-1};
|
int m_maxpos{-1};
|
||||||
|
bool m_skipZeros{false};
|
||||||
mutable std::u32string::value_type m_char;
|
mutable std::u32string::value_type m_char;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ QtcPlugin {
|
|||||||
"terminalplugin.h",
|
"terminalplugin.h",
|
||||||
"terminalprocessimpl.cpp",
|
"terminalprocessimpl.cpp",
|
||||||
"terminalprocessimpl.h",
|
"terminalprocessimpl.h",
|
||||||
|
"terminalsearch.cpp",
|
||||||
|
"terminalsearch.h",
|
||||||
"terminalsettings.cpp",
|
"terminalsettings.cpp",
|
||||||
"terminalsettings.h",
|
"terminalsettings.h",
|
||||||
"terminalsettingspage.cpp",
|
"terminalsettingspage.cpp",
|
||||||
|
|||||||
@@ -2,9 +2,11 @@
|
|||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
#include "terminalcommands.h"
|
#include "terminalcommands.h"
|
||||||
|
#include "terminaltr.h"
|
||||||
|
|
||||||
#include <coreplugin/actionmanager/actionmanager.h>
|
#include <coreplugin/actionmanager/actionmanager.h>
|
||||||
#include <coreplugin/coreconstants.h>
|
#include <coreplugin/coreconstants.h>
|
||||||
|
#include <coreplugin/find/textfindconstants.h>
|
||||||
|
|
||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
|
|
||||||
@@ -37,81 +39,87 @@ TerminalCommands::TerminalCommands() {}
|
|||||||
|
|
||||||
void TerminalCommands::init(const Core::Context &context)
|
void TerminalCommands::init(const Core::Context &context)
|
||||||
{
|
{
|
||||||
initWidgetActions(context);
|
m_context = context;
|
||||||
initPaneActions(context);
|
initWidgetActions();
|
||||||
|
initPaneActions();
|
||||||
initGlobalCommands();
|
initGlobalCommands();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerminalCommands::initWidgetActions(const Core::Context &context)
|
void TerminalCommands::registerAction(QAction &action,
|
||||||
|
const Utils::Id &id,
|
||||||
|
QList<QKeySequence> shortCuts)
|
||||||
{
|
{
|
||||||
Command *command = ActionManager::instance()->registerAction(&m_widgetActions.copy,
|
Command *cmd = ActionManager::instance()->registerAction(&action, id, m_context);
|
||||||
COPY,
|
cmd->setKeySequences(shortCuts);
|
||||||
context);
|
m_commands.push_back(cmd);
|
||||||
command->setDefaultKeySequences(
|
|
||||||
{QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+C")
|
|
||||||
: QLatin1String("Ctrl+Shift+C")),
|
|
||||||
QKeySequence(Qt::Key_Return)});
|
|
||||||
m_commands.push_back(command);
|
|
||||||
|
|
||||||
command = ActionManager::instance()->registerAction(&m_widgetActions.paste, PASTE, context);
|
|
||||||
command->setDefaultKeySequence(QKeySequence(
|
|
||||||
HostOsInfo::isMacHost() ? QLatin1String("Ctrl+V") : QLatin1String("Ctrl+Shift+V")));
|
|
||||||
m_commands.push_back(command);
|
|
||||||
|
|
||||||
command = ActionManager::instance()->registerAction(&m_widgetActions.clearSelection,
|
|
||||||
CLEARSELECTION);
|
|
||||||
command->setDefaultKeySequence(QKeySequence("Esc"));
|
|
||||||
m_commands.push_back(command);
|
|
||||||
|
|
||||||
command = ActionManager::instance()->registerAction(&m_widgetActions.moveCursorWordLeft,
|
|
||||||
MOVECURSORWORDLEFT);
|
|
||||||
command->setDefaultKeySequence(QKeySequence("Alt+Left"));
|
|
||||||
m_commands.push_back(command);
|
|
||||||
|
|
||||||
command = ActionManager::instance()->registerAction(&m_widgetActions.moveCursorWordRight,
|
|
||||||
MOVECURSORWORDRIGHT);
|
|
||||||
command->setDefaultKeySequence(QKeySequence("Alt+Right"));
|
|
||||||
m_commands.push_back(command);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerminalCommands::initPaneActions(const Core::Context &context)
|
void TerminalCommands::initWidgetActions()
|
||||||
{
|
{
|
||||||
Command *command = ActionManager::instance()->registerAction(&m_paneActions.newTerminal,
|
m_widgetActions.copy.setText(Tr::tr("Copy"));
|
||||||
NEWTERMINAL,
|
m_widgetActions.paste.setText(Tr::tr("Paste"));
|
||||||
context);
|
m_widgetActions.clearSelection.setText(Tr::tr("Clear Selection"));
|
||||||
command->setDefaultKeySequence(QKeySequence(
|
m_widgetActions.clearTerminal.setText(Tr::tr("Clear Terminal"));
|
||||||
HostOsInfo::isMacHost() ? QLatin1String("Ctrl+T") : QLatin1String("Ctrl+Shift+T")));
|
m_widgetActions.moveCursorWordLeft.setText(Tr::tr("Move Cursor Word Left"));
|
||||||
m_commands.push_back(command);
|
m_widgetActions.moveCursorWordRight.setText(Tr::tr("Move Cursor Word Right"));
|
||||||
|
m_widgetActions.findNext.setText(Tr::tr("Find Next"));
|
||||||
|
m_widgetActions.findPrevious.setText(Tr::tr("Find Previous"));
|
||||||
|
|
||||||
command = ActionManager::instance()->registerAction(&m_paneActions.closeTerminal,
|
registerAction(m_widgetActions.copy,
|
||||||
CLOSETERMINAL,
|
COPY,
|
||||||
context);
|
{QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+C")
|
||||||
command->setDefaultKeySequence(QKeySequence(
|
: QLatin1String("Ctrl+Shift+C"))});
|
||||||
HostOsInfo::isMacHost() ? QLatin1String("Ctrl+W") : QLatin1String("Ctrl+Shift+W")));
|
|
||||||
m_commands.push_back(command);
|
|
||||||
|
|
||||||
command = ActionManager::instance()->registerAction(&m_paneActions.nextTerminal,
|
registerAction(m_widgetActions.paste,
|
||||||
NEXTTERMINAL,
|
PASTE,
|
||||||
context);
|
{QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+V")
|
||||||
command->setDefaultKeySequences(
|
: QLatin1String("Ctrl+Shift+V"))});
|
||||||
{QKeySequence("ALT+TAB"),
|
|
||||||
QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+Shift+[")
|
|
||||||
: QLatin1String("Ctrl+PgUp"))});
|
|
||||||
m_commands.push_back(command);
|
|
||||||
|
|
||||||
command = ActionManager::instance()->registerAction(&m_paneActions.prevTerminal,
|
registerAction(m_widgetActions.clearSelection, CLEARSELECTION);
|
||||||
PREVTERMINAL,
|
|
||||||
context);
|
|
||||||
command->setDefaultKeySequences(
|
|
||||||
{QKeySequence("ALT+SHIFT+TAB"),
|
|
||||||
QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+Shift+]")
|
|
||||||
: QLatin1String("Ctrl+PgDown"))});
|
|
||||||
m_commands.push_back(command);
|
|
||||||
|
|
||||||
command = ActionManager::instance()->registerAction(&m_paneActions.minMax, MINMAX, context);
|
registerAction(m_widgetActions.moveCursorWordLeft,
|
||||||
command->setDefaultKeySequence(QKeySequence(
|
MOVECURSORWORDLEFT,
|
||||||
HostOsInfo::isMacHost() ? QLatin1String("Ctrl+Return") : QLatin1String("Alt+Return")));
|
{QKeySequence("Alt+Left")});
|
||||||
m_commands.push_back(command);
|
|
||||||
|
registerAction(m_widgetActions.moveCursorWordRight,
|
||||||
|
MOVECURSORWORDRIGHT,
|
||||||
|
{QKeySequence("Alt+Right")});
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerminalCommands::initPaneActions()
|
||||||
|
{
|
||||||
|
m_paneActions.newTerminal.setText(Tr::tr("New Terminal"));
|
||||||
|
m_paneActions.closeTerminal.setText(Tr::tr("Close Terminal"));
|
||||||
|
m_paneActions.nextTerminal.setText(Tr::tr("Next Terminal"));
|
||||||
|
m_paneActions.prevTerminal.setText(Tr::tr("Previous Terminal"));
|
||||||
|
m_paneActions.minMax.setText(Tr::tr("Minimize/Maximize Terminal"));
|
||||||
|
|
||||||
|
registerAction(m_paneActions.newTerminal,
|
||||||
|
NEWTERMINAL,
|
||||||
|
{QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+T")
|
||||||
|
: QLatin1String("Ctrl+Shift+T"))});
|
||||||
|
|
||||||
|
registerAction(m_paneActions.closeTerminal,
|
||||||
|
CLOSETERMINAL,
|
||||||
|
{QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+W")
|
||||||
|
: QLatin1String("Ctrl+Shift+W"))});
|
||||||
|
|
||||||
|
registerAction(m_paneActions.nextTerminal,
|
||||||
|
NEXTTERMINAL,
|
||||||
|
{QKeySequence("ALT+TAB"),
|
||||||
|
QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+Shift+[")
|
||||||
|
: QLatin1String("Ctrl+PgUp"))});
|
||||||
|
|
||||||
|
registerAction(m_paneActions.prevTerminal,
|
||||||
|
PREVTERMINAL,
|
||||||
|
{QKeySequence("ALT+SHIFT+TAB"),
|
||||||
|
QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+Shift+]")
|
||||||
|
: QLatin1String("Ctrl+PgDown"))});
|
||||||
|
|
||||||
|
registerAction(m_paneActions.minMax,
|
||||||
|
MINMAX,
|
||||||
|
{QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+Return")
|
||||||
|
: QLatin1String("Alt+Return"))});
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerminalCommands::initGlobalCommands()
|
void TerminalCommands::initGlobalCommands()
|
||||||
@@ -153,13 +161,20 @@ QAction *TerminalCommands::openSettingsAction()
|
|||||||
return ActionManager::command("Preferences.Terminal.General")->action();
|
return ActionManager::command("Preferences.Terminal.General")->action();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerminalCommands::registerOpenCloseTerminalPaneCommand()
|
void TerminalCommands::lazyInitCommand(const Utils::Id &id)
|
||||||
{
|
{
|
||||||
Command* terminalCmd = ActionManager::command("QtCreator.Pane.Terminal");
|
Command *cmd = ActionManager::command(id);
|
||||||
QTC_ASSERT(terminalCmd, return);
|
QTC_ASSERT(cmd, return);
|
||||||
|
m_commands.append(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
if (!m_commands.contains(terminalCmd))
|
void TerminalCommands::lazyInitCommands()
|
||||||
m_commands.append(terminalCmd);
|
{
|
||||||
|
static const Utils::Id terminalPaneCmd("QtCreator.Pane.Terminal");
|
||||||
|
lazyInitCommand(terminalPaneCmd);
|
||||||
|
lazyInitCommand(Core::Constants::FIND_IN_DOCUMENT);
|
||||||
|
lazyInitCommand(Core::Constants::FIND_NEXT);
|
||||||
|
lazyInitCommand(Core::Constants::FIND_PREVIOUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Terminal
|
} // namespace Terminal
|
||||||
|
|||||||
@@ -3,6 +3,10 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <utils/id.h>
|
||||||
|
|
||||||
|
#include <coreplugin/icontext.h>
|
||||||
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
@@ -10,29 +14,29 @@
|
|||||||
namespace Core {
|
namespace Core {
|
||||||
class Command;
|
class Command;
|
||||||
class Context;
|
class Context;
|
||||||
}
|
} // namespace Core
|
||||||
|
|
||||||
namespace Terminal {
|
namespace Terminal {
|
||||||
|
|
||||||
struct WidgetActions
|
struct WidgetActions
|
||||||
{
|
{
|
||||||
QAction copy{QCoreApplication::translate("QtC::Terminal", "Copy")};
|
QAction copy;
|
||||||
QAction paste{QCoreApplication::translate("QtC::Terminal", "Paste")};
|
QAction paste;
|
||||||
QAction clearSelection{QCoreApplication::translate("QtC::Terminal", "Clear Selection")};
|
QAction clearSelection;
|
||||||
QAction clearTerminal{QCoreApplication::translate("QtC::Terminal", "Clear Terminal")};
|
QAction clearTerminal;
|
||||||
QAction moveCursorWordLeft{QCoreApplication::translate("QtC::Terminal",
|
QAction moveCursorWordLeft;
|
||||||
"Move Cursor Word Left")};
|
QAction moveCursorWordRight;
|
||||||
QAction moveCursorWordRight{QCoreApplication::translate("QtC::Terminal",
|
QAction findNext;
|
||||||
"Move Cursor Word Right")};
|
QAction findPrevious;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PaneActions
|
struct PaneActions
|
||||||
{
|
{
|
||||||
QAction newTerminal{QCoreApplication::translate("QtC::Terminal", "New Terminal")};
|
QAction newTerminal;
|
||||||
QAction closeTerminal{QCoreApplication::translate("QtC::Terminal", "Close Terminal")};
|
QAction closeTerminal;
|
||||||
QAction nextTerminal{QCoreApplication::translate("QtC::Terminal", "Next Terminal")};
|
QAction nextTerminal;
|
||||||
QAction prevTerminal{QCoreApplication::translate("QtC::Terminal", "Previous Terminal")};
|
QAction prevTerminal;
|
||||||
QAction minMax{QCoreApplication::translate("QtC::Terminal", "Minimize/Maximize Terminal")};
|
QAction minMax;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TerminalCommands
|
class TerminalCommands
|
||||||
@@ -51,17 +55,21 @@ public:
|
|||||||
|
|
||||||
static QAction *openSettingsAction();
|
static QAction *openSettingsAction();
|
||||||
|
|
||||||
void registerOpenCloseTerminalPaneCommand();
|
void lazyInitCommands();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void initWidgetActions(const Core::Context &context);
|
void initWidgetActions();
|
||||||
void initPaneActions(const Core::Context &context);
|
void initPaneActions();
|
||||||
void initGlobalCommands();
|
void initGlobalCommands();
|
||||||
|
|
||||||
|
void lazyInitCommand(const Utils::Id &id);
|
||||||
|
void registerAction(QAction &action, const Utils::Id &id, QList<QKeySequence> shortcuts = {});
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WidgetActions m_widgetActions;
|
WidgetActions m_widgetActions;
|
||||||
PaneActions m_paneActions;
|
PaneActions m_paneActions;
|
||||||
QList<Core::Command *> m_commands;
|
QList<Core::Command *> m_commands;
|
||||||
|
Core::Context m_context;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Terminal
|
} // namespace Terminal
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ TerminalPane::TerminalPane(QObject *parent)
|
|||||||
, m_tabWidget(new QTabWidget)
|
, m_tabWidget(new QTabWidget)
|
||||||
{
|
{
|
||||||
setupContext("Terminal.Pane", m_tabWidget);
|
setupContext("Terminal.Pane", m_tabWidget);
|
||||||
|
setZoomButtonsEnabled(true);
|
||||||
|
|
||||||
TerminalCommands::instance().init(Core::Context("Terminal.Pane"));
|
TerminalCommands::instance().init(Core::Context("Terminal.Pane"));
|
||||||
|
|
||||||
connect(this, &IOutputPane::zoomInRequested, this, [this] {
|
connect(this, &IOutputPane::zoomInRequested, this, [this] {
|
||||||
@@ -47,16 +49,18 @@ TerminalPane::TerminalPane(QObject *parent)
|
|||||||
QAction &newTerminal = TerminalCommands::instance().paneActions().newTerminal;
|
QAction &newTerminal = TerminalCommands::instance().paneActions().newTerminal;
|
||||||
QAction &closeTerminal = TerminalCommands::instance().paneActions().closeTerminal;
|
QAction &closeTerminal = TerminalCommands::instance().paneActions().closeTerminal;
|
||||||
|
|
||||||
newTerminal.setIcon(Icon({
|
newTerminal.setIcon(
|
||||||
{":/terminal/images/terminal.png", Theme::IconsBaseColor},
|
Icon({{":/terminal/images/terminal.png", Theme::IconsBaseColor},
|
||||||
{":/utils/images/iconoverlay_add_small.png", Theme::IconsRunToolBarColor}}).icon());
|
{":/utils/images/iconoverlay_add_small.png", Theme::IconsRunToolBarColor}})
|
||||||
|
.icon());
|
||||||
newTerminal.setToolTip(Tr::tr("Create a new Terminal."));
|
newTerminal.setToolTip(Tr::tr("Create a new Terminal."));
|
||||||
|
|
||||||
connect(&newTerminal, &QAction::triggered, this, [this] { openTerminal({}); });
|
connect(&newTerminal, &QAction::triggered, this, [this] { openTerminal({}); });
|
||||||
|
|
||||||
closeTerminal.setIcon(Icon({
|
closeTerminal.setIcon(
|
||||||
{":/terminal/images/terminal.png", Theme::IconsBaseColor},
|
Icon({{":/terminal/images/terminal.png", Theme::IconsBaseColor},
|
||||||
{":/utils/images/iconoverlay_close_small.png", Theme::IconsStopToolBarColor}}).icon());
|
{":/utils/images/iconoverlay_close_small.png", Theme::IconsStopToolBarColor}})
|
||||||
|
.icon());
|
||||||
closeTerminal.setToolTip(Tr::tr("Close the current Terminal."));
|
closeTerminal.setToolTip(Tr::tr("Close the current Terminal."));
|
||||||
closeTerminal.setEnabled(false);
|
closeTerminal.setEnabled(false);
|
||||||
|
|
||||||
@@ -289,12 +293,6 @@ void TerminalPane::clearContents()
|
|||||||
t->clearContents();
|
t->clearContents();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerminalPane::visibilityChanged(bool visible)
|
|
||||||
{
|
|
||||||
if (visible)
|
|
||||||
TerminalCommands::instance().registerOpenCloseTerminalPaneCommand();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TerminalPane::setFocus()
|
void TerminalPane::setFocus()
|
||||||
{
|
{
|
||||||
if (const auto t = currentTerminal())
|
if (const auto t = currentTerminal())
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ public:
|
|||||||
QString displayName() const override;
|
QString displayName() const override;
|
||||||
int priorityInStatusBar() const override;
|
int priorityInStatusBar() const override;
|
||||||
void clearContents() override;
|
void clearContents() override;
|
||||||
void visibilityChanged(bool visible) override;
|
|
||||||
void setFocus() override;
|
void setFocus() override;
|
||||||
bool hasFocus() const override;
|
bool hasFocus() const override;
|
||||||
bool canFocus() const override;
|
bool canFocus() const override;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "terminalprocessimpl.h"
|
#include "terminalprocessimpl.h"
|
||||||
#include "terminalsettings.h"
|
#include "terminalsettings.h"
|
||||||
#include "terminalsettingspage.h"
|
#include "terminalsettingspage.h"
|
||||||
|
#include "terminalcommands.h"
|
||||||
|
|
||||||
#include <coreplugin/actionmanager/actioncontainer.h>
|
#include <coreplugin/actionmanager/actioncontainer.h>
|
||||||
#include <coreplugin/actionmanager/actionmanager.h>
|
#include <coreplugin/actionmanager/actionmanager.h>
|
||||||
@@ -35,6 +36,12 @@ TerminalPlugin::~TerminalPlugin()
|
|||||||
m_terminalPane = nullptr;
|
m_terminalPane = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TerminalPlugin::delayedInitialize()
|
||||||
|
{
|
||||||
|
TerminalCommands::instance().lazyInitCommands();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void TerminalPlugin::extensionsInitialized()
|
void TerminalPlugin::extensionsInitialized()
|
||||||
{
|
{
|
||||||
TerminalSettingsPage::instance().init();
|
TerminalSettingsPage::instance().init();
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ public:
|
|||||||
~TerminalPlugin() override;
|
~TerminalPlugin() override;
|
||||||
|
|
||||||
void extensionsInitialized() override;
|
void extensionsInitialized() override;
|
||||||
|
bool delayedInitialize() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TerminalPane *m_terminalPane{nullptr};
|
TerminalPane *m_terminalPane{nullptr};
|
||||||
|
|||||||
280
src/plugins/terminal/terminalsearch.cpp
Normal file
280
src/plugins/terminal/terminalsearch.cpp
Normal file
@@ -0,0 +1,280 @@
|
|||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#include "terminalsearch.h"
|
||||||
|
#include "terminalcommands.h"
|
||||||
|
|
||||||
|
#include <QElapsedTimer>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
|
namespace Terminal {
|
||||||
|
|
||||||
|
using namespace Terminal::Internal;
|
||||||
|
|
||||||
|
constexpr std::chrono::milliseconds debounceInterval = 100ms;
|
||||||
|
|
||||||
|
TerminalSearch::TerminalSearch(TerminalSurface *surface)
|
||||||
|
: m_surface(surface)
|
||||||
|
{
|
||||||
|
m_debounceTimer.setInterval(debounceInterval);
|
||||||
|
m_debounceTimer.setSingleShot(true);
|
||||||
|
|
||||||
|
connect(surface, &TerminalSurface::invalidated, this, &TerminalSearch::updateHits);
|
||||||
|
connect(&m_debounceTimer, &QTimer::timeout, this, &TerminalSearch::debouncedUpdateHits);
|
||||||
|
|
||||||
|
connect(&TerminalCommands::widgetActions().findNext,
|
||||||
|
&QAction::triggered,
|
||||||
|
this,
|
||||||
|
&TerminalSearch::nextHit);
|
||||||
|
connect(&TerminalCommands::widgetActions().findPrevious,
|
||||||
|
&QAction::triggered,
|
||||||
|
this,
|
||||||
|
&TerminalSearch::previousHit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerminalSearch::setCurrentSelection(std::optional<SearchHitWithText> selection)
|
||||||
|
{
|
||||||
|
m_currentSelection = selection;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerminalSearch::setSearchString(const QString &searchString, Core::FindFlags findFlags)
|
||||||
|
{
|
||||||
|
if (m_currentSearchString != searchString || m_findFlags != findFlags) {
|
||||||
|
m_currentSearchString = searchString;
|
||||||
|
m_findFlags = findFlags;
|
||||||
|
updateHits();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerminalSearch::nextHit()
|
||||||
|
{
|
||||||
|
if (m_hits.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_currentHit = (m_currentHit + 1) % m_hits.size();
|
||||||
|
emit currentHitChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerminalSearch::previousHit()
|
||||||
|
{
|
||||||
|
if (m_hits.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_currentHit = (m_currentHit - 1 + m_hits.size()) % m_hits.size();
|
||||||
|
emit currentHitChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerminalSearch::updateHits()
|
||||||
|
{
|
||||||
|
if (!m_hits.isEmpty()) {
|
||||||
|
m_hits.clear();
|
||||||
|
m_currentHit = -1;
|
||||||
|
emit hitsChanged();
|
||||||
|
emit currentHitChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_debounceTimer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isSpace(char32_t a, char32_t b)
|
||||||
|
{
|
||||||
|
if (a == std::numeric_limits<char32_t>::max())
|
||||||
|
return std::isspace(b);
|
||||||
|
else if (b == std::numeric_limits<char32_t>::max())
|
||||||
|
return std::isspace(a);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<SearchHit> TerminalSearch::search()
|
||||||
|
{
|
||||||
|
QList<SearchHit> hits;
|
||||||
|
|
||||||
|
std::function<bool(char32_t, char32_t)> compare;
|
||||||
|
|
||||||
|
if (m_findFlags.testFlag(Core::FindFlag::FindCaseSensitively))
|
||||||
|
compare = [](char32_t a, char32_t b) {
|
||||||
|
return std::tolower(a) == std::tolower(b) || isSpace(a, b);
|
||||||
|
};
|
||||||
|
else
|
||||||
|
compare = [](char32_t a, char32_t b) { return a == b || isSpace(a, b); };
|
||||||
|
|
||||||
|
if (!m_currentSearchString.isEmpty()) {
|
||||||
|
const QList<uint> asUcs4 = m_currentSearchString.toUcs4();
|
||||||
|
std::u32string searchString(asUcs4.begin(), asUcs4.end());
|
||||||
|
|
||||||
|
if (m_findFlags.testFlag(Core::FindFlag::FindWholeWords)) {
|
||||||
|
searchString.push_back(std::numeric_limits<char32_t>::max());
|
||||||
|
searchString.insert(searchString.begin(), std::numeric_limits<char32_t>::max());
|
||||||
|
}
|
||||||
|
|
||||||
|
Internal::CellIterator it = m_surface->begin();
|
||||||
|
while (it != m_surface->end()) {
|
||||||
|
it = std::search(it, m_surface->end(), searchString.begin(), searchString.end(), compare);
|
||||||
|
|
||||||
|
if (it != m_surface->end()) {
|
||||||
|
auto hit = SearchHit{it.position(),
|
||||||
|
static_cast<int>(it.position() + searchString.size())};
|
||||||
|
if (m_findFlags.testFlag(Core::FindFlag::FindWholeWords)) {
|
||||||
|
hit.start++;
|
||||||
|
hit.end--;
|
||||||
|
}
|
||||||
|
hits << hit;
|
||||||
|
it += m_currentSearchString.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hits;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<SearchHit> TerminalSearch::searchRegex()
|
||||||
|
{
|
||||||
|
QList<SearchHit> hits;
|
||||||
|
|
||||||
|
QString allText;
|
||||||
|
allText.reserve(1000);
|
||||||
|
|
||||||
|
// Contains offsets at which there are characters > 2 bytes
|
||||||
|
QList<int> adjustTable;
|
||||||
|
|
||||||
|
for (auto it = m_surface->begin(); it != m_surface->end(); ++it) {
|
||||||
|
auto chs = QChar::fromUcs4(*it);
|
||||||
|
if (chs.size() > 1)
|
||||||
|
adjustTable << (allText.size());
|
||||||
|
allText += chs;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRegularExpression re(m_currentSearchString,
|
||||||
|
m_findFlags.testFlag(Core::FindFlag::FindCaseSensitively)
|
||||||
|
? QRegularExpression::NoPatternOption
|
||||||
|
: QRegularExpression::CaseInsensitiveOption);
|
||||||
|
|
||||||
|
QRegularExpressionMatchIterator it = re.globalMatch(allText);
|
||||||
|
int adjust = 0;
|
||||||
|
auto itAdjust = adjustTable.begin();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
QRegularExpressionMatch match = it.next();
|
||||||
|
int s = match.capturedStart();
|
||||||
|
int e = match.capturedEnd();
|
||||||
|
|
||||||
|
// Update 'adjust' to account for characters > 2 bytes
|
||||||
|
if (itAdjust != adjustTable.end()) {
|
||||||
|
while (s > *itAdjust && itAdjust != adjustTable.end()) {
|
||||||
|
adjust++;
|
||||||
|
itAdjust++;
|
||||||
|
}
|
||||||
|
s -= adjust;
|
||||||
|
while (e > *itAdjust && itAdjust != adjustTable.end()) {
|
||||||
|
adjust++;
|
||||||
|
itAdjust++;
|
||||||
|
}
|
||||||
|
e -= adjust;
|
||||||
|
}
|
||||||
|
hits << SearchHit{s, e};
|
||||||
|
}
|
||||||
|
|
||||||
|
return hits;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerminalSearch::debouncedUpdateHits()
|
||||||
|
{
|
||||||
|
QElapsedTimer t;
|
||||||
|
t.start();
|
||||||
|
|
||||||
|
m_currentHit = -1;
|
||||||
|
|
||||||
|
const bool regex = m_findFlags.testFlag(Core::FindFlag::FindRegularExpression);
|
||||||
|
|
||||||
|
QList<SearchHit> hits = regex ? searchRegex() : search();
|
||||||
|
|
||||||
|
if (hits != m_hits) {
|
||||||
|
m_currentHit = -1;
|
||||||
|
if (m_currentSelection)
|
||||||
|
m_currentHit = hits.indexOf(*m_currentSelection);
|
||||||
|
|
||||||
|
if (m_currentHit == -1 && !hits.isEmpty())
|
||||||
|
m_currentHit = 0;
|
||||||
|
|
||||||
|
m_hits = hits;
|
||||||
|
emit hitsChanged();
|
||||||
|
emit currentHitChanged();
|
||||||
|
emit changed();
|
||||||
|
}
|
||||||
|
if (!m_currentSearchString.isEmpty())
|
||||||
|
qDebug() << "Search took" << t.elapsed() << "ms";
|
||||||
|
}
|
||||||
|
|
||||||
|
Core::FindFlags TerminalSearch::supportedFindFlags() const
|
||||||
|
{
|
||||||
|
return Core::FindFlag::FindCaseSensitively | Core::FindFlag::FindBackward
|
||||||
|
| Core::FindFlag::FindRegularExpression | Core::FindFlag::FindWholeWords;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerminalSearch::resetIncrementalSearch()
|
||||||
|
{
|
||||||
|
m_currentSelection.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerminalSearch::clearHighlights()
|
||||||
|
{
|
||||||
|
setSearchString("", {});
|
||||||
|
}
|
||||||
|
|
||||||
|
QString TerminalSearch::currentFindString() const
|
||||||
|
{
|
||||||
|
if (m_currentSelection)
|
||||||
|
return m_currentSelection->text;
|
||||||
|
else
|
||||||
|
return m_currentSearchString;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString TerminalSearch::completedFindString() const
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Core::IFindSupport::Result TerminalSearch::findIncremental(const QString &txt,
|
||||||
|
Core::FindFlags findFlags)
|
||||||
|
{
|
||||||
|
if (txt == m_currentSearchString) {
|
||||||
|
if (m_debounceTimer.isActive())
|
||||||
|
return Result::NotYetFound;
|
||||||
|
else if (m_hits.isEmpty())
|
||||||
|
return Result::NotFound;
|
||||||
|
else
|
||||||
|
return Result::Found;
|
||||||
|
}
|
||||||
|
|
||||||
|
setSearchString(txt, findFlags);
|
||||||
|
return Result::NotYetFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
Core::IFindSupport::Result TerminalSearch::findStep(const QString &txt, Core::FindFlags findFlags)
|
||||||
|
{
|
||||||
|
if (txt == m_currentSearchString) {
|
||||||
|
if (m_debounceTimer.isActive())
|
||||||
|
return Result::NotYetFound;
|
||||||
|
else if (m_hits.isEmpty())
|
||||||
|
return Result::NotFound;
|
||||||
|
|
||||||
|
if (findFlags.testFlag(Core::FindFlag::FindBackward))
|
||||||
|
previousHit();
|
||||||
|
else
|
||||||
|
nextHit();
|
||||||
|
|
||||||
|
return Result::Found;
|
||||||
|
}
|
||||||
|
|
||||||
|
return findIncremental(txt, findFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerminalSearch::highlightAll(const QString &txt, Core::FindFlags findFlags)
|
||||||
|
{
|
||||||
|
setSearchString(txt, findFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Terminal
|
||||||
82
src/plugins/terminal/terminalsearch.h
Normal file
82
src/plugins/terminal/terminalsearch.h
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
// 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 "terminalsurface.h"
|
||||||
|
|
||||||
|
#include <coreplugin/find/ifindsupport.h>
|
||||||
|
#include <coreplugin/find/textfindconstants.h>
|
||||||
|
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
namespace Terminal {
|
||||||
|
|
||||||
|
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); }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SearchHitWithText : SearchHit
|
||||||
|
{
|
||||||
|
QString text;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TerminalSearch : public Core::IFindSupport
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
TerminalSearch(Internal::TerminalSurface *surface);
|
||||||
|
|
||||||
|
void setCurrentSelection(std::optional<SearchHitWithText> selection);
|
||||||
|
void setSearchString(const QString &searchString, Core::FindFlags findFlags);
|
||||||
|
void nextHit();
|
||||||
|
void previousHit();
|
||||||
|
|
||||||
|
QList<SearchHit> hits() const { return m_hits; }
|
||||||
|
SearchHit currentHit() const
|
||||||
|
{
|
||||||
|
return m_currentHit >= 0 ? m_hits.at(m_currentHit) : SearchHit{};
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool supportsReplace() const override { return false; }
|
||||||
|
Core::FindFlags supportedFindFlags() const override;
|
||||||
|
void resetIncrementalSearch() override;
|
||||||
|
void clearHighlights() override;
|
||||||
|
QString currentFindString() const override;
|
||||||
|
QString completedFindString() const override;
|
||||||
|
Result findIncremental(const QString &txt, Core::FindFlags findFlags) override;
|
||||||
|
Result findStep(const QString &txt, Core::FindFlags findFlags) override;
|
||||||
|
|
||||||
|
void highlightAll(const QString &, Core::FindFlags) override;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void hitsChanged();
|
||||||
|
void currentHitChanged();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void updateHits();
|
||||||
|
void debouncedUpdateHits();
|
||||||
|
QList<SearchHit> search();
|
||||||
|
QList<SearchHit> searchRegex();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::optional<SearchHitWithText> m_currentSelection;
|
||||||
|
QString m_currentSearchString;
|
||||||
|
Core::FindFlags m_findFlags;
|
||||||
|
Internal::TerminalSurface *m_surface;
|
||||||
|
|
||||||
|
int m_currentHit{-1};
|
||||||
|
QList<SearchHit> m_hits;
|
||||||
|
QTimer m_debounceTimer;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Terminal
|
||||||
@@ -110,6 +110,11 @@ TerminalSettings::TerminalSettings()
|
|||||||
"Selection",
|
"Selection",
|
||||||
Utils::creatorTheme()->color(Theme::TerminalSelection));
|
Utils::creatorTheme()->color(Theme::TerminalSelection));
|
||||||
|
|
||||||
|
setupColor(this,
|
||||||
|
findMatchColor,
|
||||||
|
"Find matches",
|
||||||
|
Utils::creatorTheme()->color(Theme::TerminalFindMatch));
|
||||||
|
|
||||||
setupColor(this, colors[0], "0", Utils::creatorTheme()->color(Theme::TerminalAnsi0));
|
setupColor(this, colors[0], "0", Utils::creatorTheme()->color(Theme::TerminalAnsi0));
|
||||||
setupColor(this, colors[8], "8", Utils::creatorTheme()->color(Theme::TerminalAnsi8));
|
setupColor(this, colors[8], "8", Utils::creatorTheme()->color(Theme::TerminalAnsi8));
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ public:
|
|||||||
Utils::ColorAspect foregroundColor;
|
Utils::ColorAspect foregroundColor;
|
||||||
Utils::ColorAspect backgroundColor;
|
Utils::ColorAspect backgroundColor;
|
||||||
Utils::ColorAspect selectionColor;
|
Utils::ColorAspect selectionColor;
|
||||||
|
Utils::ColorAspect findMatchColor;
|
||||||
|
|
||||||
Utils::ColorAspect colors[16];
|
Utils::ColorAspect colors[16];
|
||||||
|
|
||||||
|
|||||||
@@ -399,6 +399,7 @@ QWidget *TerminalSettingsPage::widget()
|
|||||||
Tr::tr("Foreground"), settings.foregroundColor, st,
|
Tr::tr("Foreground"), settings.foregroundColor, st,
|
||||||
Tr::tr("Background"), settings.backgroundColor, st,
|
Tr::tr("Background"), settings.backgroundColor, st,
|
||||||
Tr::tr("Selection"), settings.selectionColor, st,
|
Tr::tr("Selection"), settings.selectionColor, st,
|
||||||
|
Tr::tr("Find match"), settings.findMatchColor, st,
|
||||||
},
|
},
|
||||||
Row {
|
Row {
|
||||||
settings.colors[0], settings.colors[1],
|
settings.colors[0], settings.colors[1],
|
||||||
|
|||||||
@@ -7,6 +7,10 @@
|
|||||||
#include "terminalsettings.h"
|
#include "terminalsettings.h"
|
||||||
#include "terminalsurface.h"
|
#include "terminalsurface.h"
|
||||||
|
|
||||||
|
#include <aggregation/aggregate.h>
|
||||||
|
|
||||||
|
#include <coreplugin/actionmanager/actionmanager.h>
|
||||||
|
#include <coreplugin/coreconstants.h>
|
||||||
#include <coreplugin/editormanager/editormanager.h>
|
#include <coreplugin/editormanager/editormanager.h>
|
||||||
#include <coreplugin/fileutils.h>
|
#include <coreplugin/fileutils.h>
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
@@ -48,6 +52,15 @@ using namespace Utils::Terminal;
|
|||||||
|
|
||||||
namespace Terminal {
|
namespace Terminal {
|
||||||
|
|
||||||
|
namespace ColorIndex {
|
||||||
|
enum Indices {
|
||||||
|
Foreground = Internal::ColorIndex::Foreground,
|
||||||
|
Background = Internal::ColorIndex::Background,
|
||||||
|
Selection,
|
||||||
|
FindMatch,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
// Minimum time between two refreshes. (30fps)
|
// Minimum time between two refreshes. (30fps)
|
||||||
@@ -72,7 +85,7 @@ TerminalWidget::TerminalWidget(QWidget *parent, const OpenTerminalParameters &op
|
|||||||
m_cursorBlinkState = !m_cursorBlinkState;
|
m_cursorBlinkState = !m_cursorBlinkState;
|
||||||
else
|
else
|
||||||
m_cursorBlinkState = true;
|
m_cursorBlinkState = true;
|
||||||
updateViewport(gridToViewport(QRect{m_cursor.position, m_cursor.position}));
|
updateViewportRect(gridToViewport(QRect{m_cursor.position, m_cursor.position}));
|
||||||
});
|
});
|
||||||
|
|
||||||
setAttribute(Qt::WA_InputMethodEnabled);
|
setAttribute(Qt::WA_InputMethodEnabled);
|
||||||
@@ -107,6 +120,18 @@ TerminalWidget::TerminalWidget(QWidget *parent, const OpenTerminalParameters &op
|
|||||||
setupFont();
|
setupFont();
|
||||||
configBlinkTimer();
|
configBlinkTimer();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
m_aggregate = new Aggregation::Aggregate(this);
|
||||||
|
m_aggregate->add(this);
|
||||||
|
m_aggregate->add(m_search.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
TerminalWidget::~TerminalWidget()
|
||||||
|
{
|
||||||
|
// The Aggregate stuff tries to do clever deletion of the children, but we
|
||||||
|
// we don't want that.
|
||||||
|
m_aggregate->remove(this);
|
||||||
|
m_aggregate->remove(m_search.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerminalWidget::setupPty()
|
void TerminalWidget::setupPty()
|
||||||
@@ -203,12 +228,14 @@ void TerminalWidget::setupFont()
|
|||||||
void TerminalWidget::setupColors()
|
void TerminalWidget::setupColors()
|
||||||
{
|
{
|
||||||
// Check if the colors have changed.
|
// Check if the colors have changed.
|
||||||
std::array<QColor, 18> newColors;
|
std::array<QColor, 20> newColors;
|
||||||
for (int i = 0; i < 16; ++i) {
|
for (int i = 0; i < 16; ++i) {
|
||||||
newColors[i] = TerminalSettings::instance().colors[i].value();
|
newColors[i] = TerminalSettings::instance().colors[i].value();
|
||||||
}
|
}
|
||||||
newColors[16] = TerminalSettings::instance().foregroundColor.value();
|
newColors[ColorIndex::Background] = TerminalSettings::instance().backgroundColor.value();
|
||||||
newColors[17] = TerminalSettings::instance().backgroundColor.value();
|
newColors[ColorIndex::Foreground] = TerminalSettings::instance().foregroundColor.value();
|
||||||
|
newColors[ColorIndex::Selection] = TerminalSettings::instance().selectionColor.value();
|
||||||
|
newColors[ColorIndex::FindMatch] = TerminalSettings::instance().findMatchColor.value();
|
||||||
|
|
||||||
if (m_currentColors == newColors)
|
if (m_currentColors == newColors)
|
||||||
return;
|
return;
|
||||||
@@ -250,6 +277,16 @@ void TerminalWidget::setupSurface()
|
|||||||
{
|
{
|
||||||
m_shellIntegration.reset(new ShellIntegration());
|
m_shellIntegration.reset(new ShellIntegration());
|
||||||
m_surface = std::make_unique<Internal::TerminalSurface>(QSize{80, 60}, m_shellIntegration.get());
|
m_surface = std::make_unique<Internal::TerminalSurface>(QSize{80, 60}, m_shellIntegration.get());
|
||||||
|
m_search = std::make_unique<TerminalSearch>(m_surface.get());
|
||||||
|
|
||||||
|
connect(m_search.get(), &TerminalSearch::hitsChanged, this, &TerminalWidget::updateViewport);
|
||||||
|
connect(m_search.get(), &TerminalSearch::currentHitChanged, this, [this] {
|
||||||
|
SearchHit hit = m_search->currentHit();
|
||||||
|
if (hit.start >= 0) {
|
||||||
|
setSelection(Selection{hit.start, hit.end, true}, hit != m_lastSelectedHit);
|
||||||
|
m_lastSelectedHit = hit;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
connect(m_surface.get(),
|
connect(m_surface.get(),
|
||||||
&Internal::TerminalSurface::writeToPty,
|
&Internal::TerminalSurface::writeToPty,
|
||||||
@@ -263,7 +300,8 @@ void TerminalWidget::setupSurface()
|
|||||||
this,
|
this,
|
||||||
[this](const QRect &rect) {
|
[this](const QRect &rect) {
|
||||||
setSelection(std::nullopt);
|
setSelection(std::nullopt);
|
||||||
updateViewport(gridToViewport(rect));
|
updateViewportRect(gridToViewport(rect));
|
||||||
|
verticalScrollBar()->setValue(m_surface->fullSize().height());
|
||||||
});
|
});
|
||||||
connect(m_surface.get(),
|
connect(m_surface.get(),
|
||||||
&Internal::TerminalSurface::cursorChanged,
|
&Internal::TerminalSurface::cursorChanged,
|
||||||
@@ -282,7 +320,8 @@ void TerminalWidget::setupSurface()
|
|||||||
|
|
||||||
m_cursor = newCursor;
|
m_cursor = newCursor;
|
||||||
|
|
||||||
updateViewport(gridToViewport(QRect{QPoint{startX, startY}, QPoint{endX, endY}}));
|
updateViewportRect(
|
||||||
|
gridToViewport(QRect{QPoint{startX, startY}, QPoint{endX, endY}}));
|
||||||
configBlinkTimer();
|
configBlinkTimer();
|
||||||
});
|
});
|
||||||
connect(m_surface.get(), &Internal::TerminalSurface::altscreenChanged, this, [this] {
|
connect(m_surface.get(), &Internal::TerminalSurface::altscreenChanged, this, [this] {
|
||||||
@@ -330,7 +369,7 @@ QColor TerminalWidget::toQColor(std::variant<int, QColor> color) const
|
|||||||
if (idx >= 0 && idx < 18)
|
if (idx >= 0 && idx < 18)
|
||||||
return m_currentColors[idx];
|
return m_currentColors[idx];
|
||||||
|
|
||||||
return m_currentColors[Internal::ColorIndex::Background];
|
return m_currentColors[ColorIndex::Background];
|
||||||
}
|
}
|
||||||
return std::get<QColor>(color);
|
return std::get<QColor>(color);
|
||||||
}
|
}
|
||||||
@@ -460,24 +499,34 @@ QString TerminalWidget::textFromSelection() const
|
|||||||
Internal::CellIterator end = m_surface->iteratorAt(m_selection->end);
|
Internal::CellIterator end = m_surface->iteratorAt(m_selection->end);
|
||||||
|
|
||||||
std::u32string s;
|
std::u32string s;
|
||||||
|
bool previousWasZero = false;
|
||||||
for (; it != end; ++it) {
|
for (; it != end; ++it) {
|
||||||
if (it.gridPos().x() == 0 && !s.empty())
|
if (it.gridPos().x() == 0 && !s.empty() && previousWasZero)
|
||||||
s += U'\n';
|
s += U'\n';
|
||||||
if (*it != 0)
|
|
||||||
|
if (*it != 0) {
|
||||||
|
previousWasZero = false;
|
||||||
s += *it;
|
s += *it;
|
||||||
|
} else {
|
||||||
|
previousWasZero = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return QString::fromUcs4(s.data(), static_cast<int>(s.size()));
|
return QString::fromUcs4(s.data(), static_cast<int>(s.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TerminalWidget::setSelection(const std::optional<Selection> &selection)
|
bool TerminalWidget::setSelection(const std::optional<Selection> &selection, bool scroll)
|
||||||
{
|
{
|
||||||
|
qCDebug(selectionLog) << "setSelection" << selection.has_value();
|
||||||
|
if (selection.has_value())
|
||||||
|
qCDebug(selectionLog) << "start:" << selection->start << "end:" << selection->end
|
||||||
|
<< "final:" << selection->final;
|
||||||
|
|
||||||
if (selectionLog().isDebugEnabled())
|
if (selectionLog().isDebugEnabled())
|
||||||
updateViewport();
|
updateViewport();
|
||||||
|
|
||||||
if (selection == m_selection) {
|
if (selection == m_selection)
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
m_selection = selection;
|
m_selection = selection;
|
||||||
|
|
||||||
@@ -485,13 +534,25 @@ bool TerminalWidget::setSelection(const std::optional<Selection> &selection)
|
|||||||
|
|
||||||
if (m_selection && m_selection->final) {
|
if (m_selection && m_selection->final) {
|
||||||
qCDebug(selectionLog) << "Copy enabled:" << selection.has_value();
|
qCDebug(selectionLog) << "Copy enabled:" << selection.has_value();
|
||||||
|
QString text = textFromSelection();
|
||||||
|
|
||||||
QClipboard *clipboard = QApplication::clipboard();
|
QClipboard *clipboard = QApplication::clipboard();
|
||||||
if (clipboard->supportsSelection()) {
|
if (clipboard->supportsSelection()) {
|
||||||
QString text = textFromSelection();
|
|
||||||
qCDebug(selectionLog) << "Selection set to clipboard: " << text;
|
qCDebug(selectionLog) << "Selection set to clipboard: " << text;
|
||||||
clipboard->setText(text, QClipboard::Selection);
|
clipboard->setText(text, QClipboard::Selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (scroll) {
|
||||||
|
QPoint start = m_surface->posToGrid(m_selection->start);
|
||||||
|
QPoint end = m_surface->posToGrid(m_selection->end);
|
||||||
|
QRect viewRect = gridToViewport(QRect{start, end});
|
||||||
|
if (viewRect.y() >= viewport()->height() || viewRect.y() < 0) {
|
||||||
|
// Selection is outside of the viewport, scroll to it.
|
||||||
|
verticalScrollBar()->setValue(start.y());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_search->setCurrentSelection(SearchHitWithText{{selection->start, selection->end}, text});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!selectionLog().isDebugEnabled())
|
if (!selectionLog().isDebugEnabled())
|
||||||
@@ -727,32 +788,64 @@ static void drawTextItemDecoration(QPainter &painter,
|
|||||||
painter.setBrush(oldBrush);
|
painter.setBrush(oldBrush);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerminalWidget::paintSelectionOrBackground(QPainter &p,
|
bool TerminalWidget::paintFindMatches(QPainter &p,
|
||||||
const Internal::TerminalCell &cell,
|
QList<SearchHit>::const_iterator &it,
|
||||||
const QRectF &cellRect,
|
const QRectF &cellRect,
|
||||||
const QPoint gridPos) const
|
const QPoint gridPos) const
|
||||||
|
{
|
||||||
|
if (it == m_search->hits().constEnd())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const int pos = m_surface->gridToPos(gridPos);
|
||||||
|
while (it != m_search->hits().constEnd()) {
|
||||||
|
if (pos < it->start)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (pos >= it->end) {
|
||||||
|
++it;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (it == m_search->hits().constEnd())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
p.fillRect(cellRect, m_currentColors[ColorIndex::FindMatch]);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TerminalWidget::paintSelection(QPainter &p, const QRectF &cellRect, const QPoint gridPos) const
|
||||||
{
|
{
|
||||||
bool isInSelection = false;
|
bool isInSelection = false;
|
||||||
|
const int pos = m_surface->gridToPos(gridPos);
|
||||||
|
|
||||||
if (m_selection) {
|
if (m_selection) {
|
||||||
const int pos = m_surface->gridToPos(gridPos);
|
|
||||||
isInSelection = pos >= m_selection->start && pos < m_selection->end;
|
isInSelection = pos >= m_selection->start && pos < m_selection->end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isInSelection)
|
if (isInSelection) {
|
||||||
p.fillRect(cellRect, TerminalSettings::instance().selectionColor.value());
|
p.fillRect(cellRect, m_currentColors[ColorIndex::Selection]);
|
||||||
else if (!(std::holds_alternative<int>(cell.backgroundColor)
|
}
|
||||||
&& std::get<int>(cell.backgroundColor) == 17))
|
|
||||||
p.fillRect(cellRect, toQColor(cell.backgroundColor));
|
return isInSelection;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TerminalWidget::paintCell(QPainter &p,
|
int TerminalWidget::paintCell(QPainter &p,
|
||||||
const QRectF &cellRect,
|
const QRectF &cellRect,
|
||||||
QPoint gridPos,
|
QPoint gridPos,
|
||||||
const Internal::TerminalCell &cell,
|
const Internal::TerminalCell &cell,
|
||||||
QFont &f) const
|
QFont &f,
|
||||||
|
QList<SearchHit>::const_iterator &searchIt) const
|
||||||
{
|
{
|
||||||
paintSelectionOrBackground(p, cell, cellRect, gridPos);
|
bool paintBackground = !paintSelection(p, cellRect, gridPos)
|
||||||
|
&& !paintFindMatches(p, searchIt, cellRect, gridPos);
|
||||||
|
|
||||||
|
bool isDefaultBg = std::holds_alternative<int>(cell.backgroundColor)
|
||||||
|
&& std::get<int>(cell.backgroundColor) == 17;
|
||||||
|
|
||||||
|
if (paintBackground && !isDefaultBg)
|
||||||
|
p.fillRect(cellRect, toQColor(cell.backgroundColor));
|
||||||
|
|
||||||
p.setPen(toQColor(cell.foregroundColor));
|
p.setPen(toQColor(cell.foregroundColor));
|
||||||
|
|
||||||
@@ -865,6 +958,14 @@ void TerminalWidget::paintCells(QPainter &p, QPaintEvent *event) const
|
|||||||
qCeil((event->rect().y() + event->rect().height()) / m_cellSize.height())
|
qCeil((event->rect().y() + event->rect().height()) / m_cellSize.height())
|
||||||
+ scrollOffset);
|
+ scrollOffset);
|
||||||
|
|
||||||
|
QList<SearchHit>::const_iterator searchIt
|
||||||
|
= std::lower_bound(m_search->hits().constBegin(),
|
||||||
|
m_search->hits().constEnd(),
|
||||||
|
startRow,
|
||||||
|
[this](const SearchHit &hit, int value) {
|
||||||
|
return m_surface->posToGrid(hit.start).y() < value;
|
||||||
|
});
|
||||||
|
|
||||||
for (int cellY = startRow; cellY < endRow; ++cellY) {
|
for (int cellY = startRow; cellY < endRow; ++cellY) {
|
||||||
for (int cellX = 0; cellX < m_surface->liveSize().width();) {
|
for (int cellX = 0; cellX < m_surface->liveSize().width();) {
|
||||||
const auto cell = m_surface->fetchCell(cellX, cellY);
|
const auto cell = m_surface->fetchCell(cellX, cellY);
|
||||||
@@ -872,7 +973,7 @@ void TerminalWidget::paintCells(QPainter &p, QPaintEvent *event) const
|
|||||||
QRectF cellRect(gridToGlobal({cellX, cellY}),
|
QRectF cellRect(gridToGlobal({cellX, cellY}),
|
||||||
QSizeF{m_cellSize.width() * cell.width, m_cellSize.height()});
|
QSizeF{m_cellSize.width() * cell.width, m_cellSize.height()});
|
||||||
|
|
||||||
int numCells = paintCell(p, cellRect, {cellX, cellY}, cell, f);
|
int numCells = paintCell(p, cellRect, {cellX, cellY}, cell, f, searchIt);
|
||||||
|
|
||||||
cellX += numCells;
|
cellX += numCells;
|
||||||
}
|
}
|
||||||
@@ -907,7 +1008,7 @@ void TerminalWidget::paintEvent(QPaintEvent *event)
|
|||||||
if (paintLog().isDebugEnabled())
|
if (paintLog().isDebugEnabled())
|
||||||
p.fillRect(event->rect(), QColor::fromRgb(rand() % 60, rand() % 60, rand() % 60));
|
p.fillRect(event->rect(), QColor::fromRgb(rand() % 60, rand() % 60, rand() % 60));
|
||||||
else
|
else
|
||||||
p.fillRect(event->rect(), m_currentColors[Internal::ColorIndex::Background]);
|
p.fillRect(event->rect(), m_currentColors[ColorIndex::Background]);
|
||||||
|
|
||||||
int scrollOffset = verticalScrollBar()->value();
|
int scrollOffset = verticalScrollBar()->value();
|
||||||
int offset = -(scrollOffset * m_cellSize.height());
|
int offset = -(scrollOffset * m_cellSize.height());
|
||||||
@@ -923,7 +1024,7 @@ void TerminalWidget::paintEvent(QPaintEvent *event)
|
|||||||
p.restore();
|
p.restore();
|
||||||
|
|
||||||
p.fillRect(QRectF{{0, 0}, QSizeF{(qreal) width(), topMargin()}},
|
p.fillRect(QRectF{{0, 0}, QSizeF{(qreal) width(), topMargin()}},
|
||||||
m_currentColors[Internal::ColorIndex::Background]);
|
m_currentColors[ColorIndex::Background]);
|
||||||
|
|
||||||
if (selectionLog().isDebugEnabled()) {
|
if (selectionLog().isDebugEnabled()) {
|
||||||
if (m_selection)
|
if (m_selection)
|
||||||
@@ -946,8 +1047,20 @@ void TerminalWidget::keyPressEvent(QKeyEvent *event)
|
|||||||
m_cursorBlinkState = true;
|
m_cursorBlinkState = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event->key() == Qt::Key_Escape) {
|
||||||
|
if (m_selection)
|
||||||
|
TerminalCommands::widgetActions().clearSelection.trigger();
|
||||||
|
else {
|
||||||
|
QTC_ASSERT(Core::ActionManager::command(Core::Constants::S_RETURNTOEDITOR), return);
|
||||||
|
Core::ActionManager::command(Core::Constants::S_RETURNTOEDITOR)->action()->trigger();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto oldSelection = m_selection;
|
||||||
if (TerminalCommands::triggerAction(event)) {
|
if (TerminalCommands::triggerAction(event)) {
|
||||||
setSelection(std::nullopt);
|
if (oldSelection && oldSelection == m_selection)
|
||||||
|
setSelection(std::nullopt);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1023,7 +1136,7 @@ void TerminalWidget::updateViewport()
|
|||||||
viewport()->update();
|
viewport()->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerminalWidget::updateViewport(const QRect &rect)
|
void TerminalWidget::updateViewportRect(const QRect &rect)
|
||||||
{
|
{
|
||||||
viewport()->update(rect);
|
viewport()->update(rect);
|
||||||
}
|
}
|
||||||
@@ -1297,7 +1410,7 @@ bool TerminalWidget::event(QEvent *event)
|
|||||||
|
|
||||||
if (event->type() == QEvent::Paint) {
|
if (event->type() == QEvent::Paint) {
|
||||||
QPainter p(this);
|
QPainter p(this);
|
||||||
p.fillRect(QRect(QPoint(0, 0), size()), m_currentColors[Internal::ColorIndex::Background]);
|
p.fillRect(QRect(QPoint(0, 0), size()), m_currentColors[ColorIndex::Background]);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,11 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "terminalsearch.h"
|
||||||
#include "terminalsurface.h"
|
#include "terminalsurface.h"
|
||||||
|
|
||||||
|
#include <aggregation/aggregate.h>
|
||||||
|
|
||||||
#include <utils/link.h>
|
#include <utils/link.h>
|
||||||
#include <utils/qtcprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/terminalhooks.h>
|
#include <utils/terminalhooks.h>
|
||||||
@@ -26,6 +29,7 @@ class TerminalWidget : public QAbstractScrollArea
|
|||||||
public:
|
public:
|
||||||
TerminalWidget(QWidget *parent = nullptr,
|
TerminalWidget(QWidget *parent = nullptr,
|
||||||
const Utils::Terminal::OpenTerminalParameters &openParameters = {});
|
const Utils::Terminal::OpenTerminalParameters &openParameters = {});
|
||||||
|
~TerminalWidget() override;
|
||||||
|
|
||||||
void setFont(const QFont &font);
|
void setFont(const QFont &font);
|
||||||
|
|
||||||
@@ -42,6 +46,8 @@ public:
|
|||||||
|
|
||||||
void clearContents();
|
void clearContents();
|
||||||
|
|
||||||
|
TerminalSearch *search() { return m_search.get(); }
|
||||||
|
|
||||||
struct Selection
|
struct Selection
|
||||||
{
|
{
|
||||||
int start;
|
int start;
|
||||||
@@ -113,14 +119,16 @@ protected:
|
|||||||
const QRectF &cellRect,
|
const QRectF &cellRect,
|
||||||
QPoint gridPos,
|
QPoint gridPos,
|
||||||
const Internal::TerminalCell &cell,
|
const Internal::TerminalCell &cell,
|
||||||
QFont &f) const;
|
QFont &f,
|
||||||
|
QList<SearchHit>::const_iterator &searchIt) const;
|
||||||
void paintCells(QPainter &painter, QPaintEvent *event) const;
|
void paintCells(QPainter &painter, QPaintEvent *event) const;
|
||||||
void paintCursor(QPainter &painter) const;
|
void paintCursor(QPainter &painter) const;
|
||||||
void paintPreedit(QPainter &painter) const;
|
void paintPreedit(QPainter &painter) const;
|
||||||
void paintSelectionOrBackground(QPainter &painter,
|
bool paintFindMatches(QPainter &painter,
|
||||||
const Internal::TerminalCell &cell,
|
QList<SearchHit>::const_iterator &searchIt,
|
||||||
const QRectF &cellRect,
|
const QRectF &cellRect,
|
||||||
const QPoint gridPos) const;
|
const QPoint gridPos) const;
|
||||||
|
bool paintSelection(QPainter &painter, const QRectF &cellRect, const QPoint gridPos) const;
|
||||||
void paintDebugSelection(QPainter &painter, const Selection &selection) const;
|
void paintDebugSelection(QPainter &painter, const Selection &selection) const;
|
||||||
|
|
||||||
qreal topMargin() const;
|
qreal topMargin() const;
|
||||||
@@ -132,7 +140,7 @@ protected:
|
|||||||
QRect gridToViewport(QRect rect) const;
|
QRect gridToViewport(QRect rect) const;
|
||||||
|
|
||||||
void updateViewport();
|
void updateViewport();
|
||||||
void updateViewport(const QRect &rect);
|
void updateViewportRect(const QRect &rect);
|
||||||
|
|
||||||
int textLineFromPixel(int y) const;
|
int textLineFromPixel(int y) const;
|
||||||
std::optional<int> textPosFromPoint(const QTextLayout &textLayout, QPoint p) const;
|
std::optional<int> textPosFromPoint(const QTextLayout &textLayout, QPoint p) const;
|
||||||
@@ -156,7 +164,7 @@ protected:
|
|||||||
|
|
||||||
void flushVTerm(bool force);
|
void flushVTerm(bool force);
|
||||||
|
|
||||||
bool setSelection(const std::optional<Selection> &selection);
|
bool setSelection(const std::optional<Selection> &selection, bool scroll = true);
|
||||||
QString textFromSelection() const;
|
QString textFromSelection() const;
|
||||||
|
|
||||||
void configBlinkTimer();
|
void configBlinkTimer();
|
||||||
@@ -194,7 +202,7 @@ private:
|
|||||||
QTimer m_scrollTimer;
|
QTimer m_scrollTimer;
|
||||||
int m_scrollDirection{0};
|
int m_scrollDirection{0};
|
||||||
|
|
||||||
std::array<QColor, 18> m_currentColors;
|
std::array<QColor, 20> m_currentColors;
|
||||||
|
|
||||||
Utils::Terminal::OpenTerminalParameters m_openParameters;
|
Utils::Terminal::OpenTerminalParameters m_openParameters;
|
||||||
|
|
||||||
@@ -208,6 +216,11 @@ private:
|
|||||||
|
|
||||||
Utils::FilePath m_cwd;
|
Utils::FilePath m_cwd;
|
||||||
Utils::CommandLine m_currentCommand;
|
Utils::CommandLine m_currentCommand;
|
||||||
|
|
||||||
|
std::unique_ptr<TerminalSearch> m_search;
|
||||||
|
|
||||||
|
Aggregation::Aggregate *m_aggregate{nullptr};
|
||||||
|
SearchHit m_lastSelectedHit{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Terminal
|
} // namespace Terminal
|
||||||
|
|||||||
Reference in New Issue
Block a user