forked from qt-creator/qt-creator
Terminal: Improve link copy
* Show link if control key is pressed (without mouse move) * Copy link on Control+Shift+Click * Add Copy Link Action to Right click menu Change-Id: Ide4ff4e77c03e015117c67f09c9d60dedd14dfcb Reviewed-by: Cristian Adam <cristian.adam@qt.io>
This commit is contained in:
@@ -20,6 +20,7 @@ namespace Terminal {
|
|||||||
|
|
||||||
constexpr char COPY[] = "Terminal.Copy";
|
constexpr char COPY[] = "Terminal.Copy";
|
||||||
constexpr char PASTE[] = "Terminal.Paste";
|
constexpr char PASTE[] = "Terminal.Paste";
|
||||||
|
constexpr char COPY_LINK[] = "Terminal.CopyLink";
|
||||||
constexpr char CLEARSELECTION[] = "Terminal.ClearSelection";
|
constexpr char CLEARSELECTION[] = "Terminal.ClearSelection";
|
||||||
constexpr char MOVECURSORWORDLEFT[] = "Terminal.MoveCursorWordLeft";
|
constexpr char MOVECURSORWORDLEFT[] = "Terminal.MoveCursorWordLeft";
|
||||||
constexpr char MOVECURSORWORDRIGHT[] = "Terminal.MoveCursorWordRight";
|
constexpr char MOVECURSORWORDRIGHT[] = "Terminal.MoveCursorWordRight";
|
||||||
@@ -59,6 +60,7 @@ void TerminalCommands::initWidgetActions()
|
|||||||
{
|
{
|
||||||
m_widgetActions.copy.setText(Tr::tr("Copy"));
|
m_widgetActions.copy.setText(Tr::tr("Copy"));
|
||||||
m_widgetActions.paste.setText(Tr::tr("Paste"));
|
m_widgetActions.paste.setText(Tr::tr("Paste"));
|
||||||
|
m_widgetActions.copyLink.setText(Tr::tr("Copy Link"));
|
||||||
m_widgetActions.clearSelection.setText(Tr::tr("Clear Selection"));
|
m_widgetActions.clearSelection.setText(Tr::tr("Clear Selection"));
|
||||||
m_widgetActions.clearTerminal.setText(Tr::tr("Clear Terminal"));
|
m_widgetActions.clearTerminal.setText(Tr::tr("Clear Terminal"));
|
||||||
m_widgetActions.moveCursorWordLeft.setText(Tr::tr("Move Cursor Word Left"));
|
m_widgetActions.moveCursorWordLeft.setText(Tr::tr("Move Cursor Word Left"));
|
||||||
@@ -76,6 +78,8 @@ void TerminalCommands::initWidgetActions()
|
|||||||
{QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+V")
|
{QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+V")
|
||||||
: QLatin1String("Ctrl+Shift+V"))});
|
: QLatin1String("Ctrl+Shift+V"))});
|
||||||
|
|
||||||
|
registerAction(m_widgetActions.copyLink, COPY_LINK);
|
||||||
|
|
||||||
registerAction(m_widgetActions.clearSelection, CLEARSELECTION);
|
registerAction(m_widgetActions.clearSelection, CLEARSELECTION);
|
||||||
|
|
||||||
registerAction(m_widgetActions.moveCursorWordLeft,
|
registerAction(m_widgetActions.moveCursorWordLeft,
|
||||||
|
@@ -22,6 +22,7 @@ struct WidgetActions
|
|||||||
{
|
{
|
||||||
QAction copy;
|
QAction copy;
|
||||||
QAction paste;
|
QAction paste;
|
||||||
|
QAction copyLink;
|
||||||
QAction clearSelection;
|
QAction clearSelection;
|
||||||
QAction clearTerminal;
|
QAction clearTerminal;
|
||||||
QAction moveCursorWordLeft;
|
QAction moveCursorWordLeft;
|
||||||
|
@@ -262,6 +262,7 @@ void TerminalWidget::setupActions()
|
|||||||
// clang-format off
|
// clang-format off
|
||||||
connect(&a.copy, &QAction::triggered, this, ifHasFocus(&TerminalWidget::copyToClipboard));
|
connect(&a.copy, &QAction::triggered, this, ifHasFocus(&TerminalWidget::copyToClipboard));
|
||||||
connect(&a.paste, &QAction::triggered, this, ifHasFocus(&TerminalWidget::pasteFromClipboard));
|
connect(&a.paste, &QAction::triggered, this, ifHasFocus(&TerminalWidget::pasteFromClipboard));
|
||||||
|
connect(&a.copyLink, &QAction::triggered, this, ifHasFocus(&TerminalWidget::copyLinkToClipboard));
|
||||||
connect(&a.clearSelection, &QAction::triggered, this, ifHasFocus(&TerminalWidget::clearSelection));
|
connect(&a.clearSelection, &QAction::triggered, this, ifHasFocus(&TerminalWidget::clearSelection));
|
||||||
connect(&a.clearTerminal, &QAction::triggered, this, ifHasFocus(&TerminalWidget::clearContents));
|
connect(&a.clearTerminal, &QAction::triggered, this, ifHasFocus(&TerminalWidget::clearContents));
|
||||||
connect(&a.moveCursorWordLeft, &QAction::triggered, this, ifHasFocus(&TerminalWidget::moveCursorWordLeft));
|
connect(&a.moveCursorWordLeft, &QAction::triggered, this, ifHasFocus(&TerminalWidget::moveCursorWordLeft));
|
||||||
@@ -390,6 +391,7 @@ void TerminalWidget::updateCopyState()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
TerminalCommands::widgetActions().copy.setEnabled(m_selection.has_value());
|
TerminalCommands::widgetActions().copy.setEnabled(m_selection.has_value());
|
||||||
|
TerminalCommands::widgetActions().copyLink.setEnabled(m_linkSelection.has_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerminalWidget::setFont(const QFont &font)
|
void TerminalWidget::setFont(const QFont &font)
|
||||||
@@ -436,6 +438,12 @@ void TerminalWidget::pasteFromClipboard()
|
|||||||
m_surface->pasteFromClipboard(clipboardText);
|
m_surface->pasteFromClipboard(clipboardText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TerminalWidget::copyLinkToClipboard()
|
||||||
|
{
|
||||||
|
if (m_linkSelection)
|
||||||
|
setClipboardAndSelection(m_linkSelection->link.targetFilePath.toUserOutput());
|
||||||
|
}
|
||||||
|
|
||||||
void TerminalWidget::clearSelection()
|
void TerminalWidget::clearSelection()
|
||||||
{
|
{
|
||||||
setSelection(std::nullopt);
|
setSelection(std::nullopt);
|
||||||
@@ -1086,11 +1094,27 @@ void TerminalWidget::keyPressEvent(QKeyEvent *event)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event->key() == Qt::Key_Control) {
|
||||||
|
if (!m_linkSelection.has_value() && checkLinkAt(mapFromGlobal(QCursor::pos()))) {
|
||||||
|
setCursor(Qt::PointingHandCursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
event->accept();
|
event->accept();
|
||||||
|
|
||||||
m_surface->sendKey(event);
|
m_surface->sendKey(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TerminalWidget::keyReleaseEvent(QKeyEvent *event)
|
||||||
|
{
|
||||||
|
if (event->key() == Qt::Key_Control && m_linkSelection.has_value()) {
|
||||||
|
m_linkSelection.reset();
|
||||||
|
updateCopyState();
|
||||||
|
setCursor(Qt::IBeamCursor);
|
||||||
|
updateViewport();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TerminalWidget::applySizeChange()
|
void TerminalWidget::applySizeChange()
|
||||||
{
|
{
|
||||||
QSize newLiveSize = {
|
QSize newLiveSize = {
|
||||||
@@ -1198,8 +1222,13 @@ void TerminalWidget::mousePressEvent(QMouseEvent *event)
|
|||||||
|
|
||||||
m_activeMouseSelect.start = viewportToGlobal(event->pos());
|
m_activeMouseSelect.start = viewportToGlobal(event->pos());
|
||||||
|
|
||||||
if (event->button() == Qt::LeftButton && event->modifiers() == Qt::ControlModifier) {
|
if (event->button() == Qt::LeftButton && event->modifiers() & Qt::ControlModifier) {
|
||||||
if (m_linkSelection) {
|
if (m_linkSelection) {
|
||||||
|
if (event->modifiers() & Qt::ShiftModifier) {
|
||||||
|
copyLinkToClipboard();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_linkSelection->link.targetFilePath.scheme().toString().startsWith("http")) {
|
if (m_linkSelection->link.targetFilePath.scheme().toString().startsWith("http")) {
|
||||||
QDesktopServices::openUrl(m_linkSelection->link.targetFilePath.toUrl());
|
QDesktopServices::openUrl(m_linkSelection->link.targetFilePath.toUrl());
|
||||||
return;
|
return;
|
||||||
@@ -1231,10 +1260,11 @@ void TerminalWidget::mousePressEvent(QMouseEvent *event)
|
|||||||
event->accept();
|
event->accept();
|
||||||
updateViewport();
|
updateViewport();
|
||||||
} else if (event->button() == Qt::RightButton) {
|
} else if (event->button() == Qt::RightButton) {
|
||||||
if (event->modifiers() == Qt::ShiftModifier) {
|
if (event->modifiers() & Qt::ShiftModifier) {
|
||||||
QMenu *contextMenu = new QMenu(this);
|
QMenu *contextMenu = new QMenu(this);
|
||||||
contextMenu->addAction(&TerminalCommands::widgetActions().copy);
|
contextMenu->addAction(&TerminalCommands::widgetActions().copy);
|
||||||
contextMenu->addAction(&TerminalCommands::widgetActions().paste);
|
contextMenu->addAction(&TerminalCommands::widgetActions().paste);
|
||||||
|
contextMenu->addAction(&TerminalCommands::widgetActions().copyLink);
|
||||||
contextMenu->addSeparator();
|
contextMenu->addSeparator();
|
||||||
contextMenu->addAction(&TerminalCommands::widgetActions().clearTerminal);
|
contextMenu->addAction(&TerminalCommands::widgetActions().clearTerminal);
|
||||||
contextMenu->addSeparator();
|
contextMenu->addSeparator();
|
||||||
@@ -1303,10 +1333,11 @@ void TerminalWidget::mouseMoveEvent(QMouseEvent *event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
setSelection(newSelection);
|
setSelection(newSelection);
|
||||||
} else if (event->modifiers() == Qt::ControlModifier) {
|
} else if (event->modifiers() & Qt::ControlModifier) {
|
||||||
checkLinkAt(event->pos());
|
checkLinkAt(event->pos());
|
||||||
} else if (m_linkSelection) {
|
} else if (m_linkSelection) {
|
||||||
m_linkSelection.reset();
|
m_linkSelection.reset();
|
||||||
|
updateCopyState();
|
||||||
updateViewport();
|
updateViewport();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1317,7 +1348,7 @@ void TerminalWidget::mouseMoveEvent(QMouseEvent *event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerminalWidget::checkLinkAt(const QPoint &pos)
|
bool TerminalWidget::checkLinkAt(const QPoint &pos)
|
||||||
{
|
{
|
||||||
const TextAndOffsets hit = textAt(pos);
|
const TextAndOffsets hit = textAt(pos);
|
||||||
|
|
||||||
@@ -1325,34 +1356,35 @@ void TerminalWidget::checkLinkAt(const QPoint &pos)
|
|||||||
QString t = QString::fromUcs4(hit.text.c_str(), hit.text.size()).trimmed();
|
QString t = QString::fromUcs4(hit.text.c_str(), hit.text.size()).trimmed();
|
||||||
t = chopIfEndsWith(t, ':');
|
t = chopIfEndsWith(t, ':');
|
||||||
|
|
||||||
if (t.isEmpty())
|
if (!t.isEmpty()) {
|
||||||
return;
|
if (t.startsWith("~/"))
|
||||||
|
t = QDir::homePath() + t.mid(1);
|
||||||
|
|
||||||
if (t.startsWith("~/")) {
|
Link link = Link::fromString(t, true);
|
||||||
t = QDir::homePath() + t.mid(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
Link link = Link::fromString(t, true);
|
if (!link.targetFilePath.isAbsolutePath())
|
||||||
|
link.targetFilePath = m_cwd.pathAppended(link.targetFilePath.path());
|
||||||
|
|
||||||
if (!link.targetFilePath.isAbsolutePath())
|
if (link.hasValidTarget()
|
||||||
link.targetFilePath = m_cwd.pathAppended(link.targetFilePath.path());
|
&& (link.targetFilePath.scheme().toString().startsWith("http")
|
||||||
|
|| link.targetFilePath.exists())) {
|
||||||
if (link.hasValidTarget()
|
const LinkSelection newSelection = LinkSelection{{hit.start, hit.end}, link};
|
||||||
&& (link.targetFilePath.scheme().toString().startsWith("http")
|
if (!m_linkSelection || *m_linkSelection != newSelection) {
|
||||||
|| link.targetFilePath.exists())) {
|
m_linkSelection = newSelection;
|
||||||
const LinkSelection newSelection = LinkSelection{{hit.start, hit.end}, link};
|
updateViewport();
|
||||||
if (!m_linkSelection || *m_linkSelection != newSelection) {
|
updateCopyState();
|
||||||
m_linkSelection = newSelection;
|
}
|
||||||
updateViewport();
|
return true;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_linkSelection) {
|
if (m_linkSelection) {
|
||||||
m_linkSelection.reset();
|
m_linkSelection.reset();
|
||||||
|
updateCopyState();
|
||||||
updateViewport();
|
updateViewport();
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerminalWidget::mouseReleaseEvent(QMouseEvent *event)
|
void TerminalWidget::mouseReleaseEvent(QMouseEvent *event)
|
||||||
|
@@ -35,6 +35,7 @@ public:
|
|||||||
|
|
||||||
void copyToClipboard();
|
void copyToClipboard();
|
||||||
void pasteFromClipboard();
|
void pasteFromClipboard();
|
||||||
|
void copyLinkToClipboard();
|
||||||
|
|
||||||
void clearSelection();
|
void clearSelection();
|
||||||
|
|
||||||
@@ -90,6 +91,7 @@ signals:
|
|||||||
protected:
|
protected:
|
||||||
void paintEvent(QPaintEvent *event) override;
|
void paintEvent(QPaintEvent *event) override;
|
||||||
void keyPressEvent(QKeyEvent *event) override;
|
void keyPressEvent(QKeyEvent *event) override;
|
||||||
|
void keyReleaseEvent(QKeyEvent *event) override;
|
||||||
void resizeEvent(QResizeEvent *event) override;
|
void resizeEvent(QResizeEvent *event) override;
|
||||||
void wheelEvent(QWheelEvent *event) override;
|
void wheelEvent(QWheelEvent *event) override;
|
||||||
void focusInEvent(QFocusEvent *event) override;
|
void focusInEvent(QFocusEvent *event) override;
|
||||||
@@ -148,7 +150,7 @@ protected:
|
|||||||
std::optional<QTextLayout::FormatRange> selectionToFormatRange(
|
std::optional<QTextLayout::FormatRange> selectionToFormatRange(
|
||||||
TerminalWidget::Selection selection, const QTextLayout &layout, int rowOffset) const;
|
TerminalWidget::Selection selection, const QTextLayout &layout, int rowOffset) const;
|
||||||
|
|
||||||
void checkLinkAt(const QPoint &pos);
|
bool checkLinkAt(const QPoint &pos);
|
||||||
|
|
||||||
struct TextAndOffsets
|
struct TextAndOffsets
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user