diff --git a/src/EditProfileDialog.cpp b/src/EditProfileDialog.cpp index cc1029f91..8e44df606 100644 --- a/src/EditProfileDialog.cpp +++ b/src/EditProfileDialog.cpp @@ -991,6 +991,10 @@ void EditProfileDialog::setupMousePage(const Profile::Ptr profile) _ui->copyTextToClipboardButton , Profile::AutoCopySelectedText, SLOT(toggleCopyTextToClipboard(bool)) }, + { + _ui->trimTrailingSpacesButton , Profile::TrimTrailingSpacesInSelectedText, + SLOT(toggleTrimTrailingSpacesInSelectedText(bool)) + }, { _ui->openLinksByDirectClickButton , Profile::OpenLinksByDirectClickEnabled, SLOT(toggleOpenLinksByDirectClick(bool)) @@ -1134,6 +1138,10 @@ void EditProfileDialog::toggleCopyTextToClipboard(bool enable) { updateTempProfileProperty(Profile::AutoCopySelectedText, enable); } +void EditProfileDialog::toggleTrimTrailingSpacesInSelectedText(bool enable) +{ + updateTempProfileProperty(Profile::TrimTrailingSpacesInSelectedText, enable); +} void EditProfileDialog::pasteFromX11Selection() { updateTempProfileProperty(Profile::MiddleClickPasteMode, Enum::PasteFromX11Selection); diff --git a/src/EditProfileDialog.h b/src/EditProfileDialog.h index 8d348c469..c85bd11b3 100644 --- a/src/EditProfileDialog.h +++ b/src/EditProfileDialog.h @@ -152,6 +152,7 @@ private slots: void toggleOpenLinksByDirectClick(bool); void toggleCtrlRequiredForDrag(bool); void toggleCopyTextToClipboard(bool); + void toggleTrimTrailingSpacesInSelectedText(bool); void pasteFromX11Selection(); void pasteFromClipboard(); diff --git a/src/EditProfileDialog.ui b/src/EditProfileDialog.ui index b43243497..45eafcc89 100644 --- a/src/EditProfileDialog.ui +++ b/src/EditProfileDialog.ui @@ -784,6 +784,16 @@ + + + + Trim trailing spaces in selected text, useful in some instances + + + Trim trailing spaces + + + diff --git a/src/Profile.cpp b/src/Profile.cpp index 58b753b52..e81433f0a 100644 --- a/src/Profile.cpp +++ b/src/Profile.cpp @@ -107,6 +107,7 @@ const Profile::PropertyInfo Profile::DefaultPropertyNames[] = { , { OpenLinksByDirectClickEnabled , "OpenLinksByDirectClickEnabled" , INTERACTION_GROUP , QVariant::Bool } , { CtrlRequiredForDrag, "CtrlRequiredForDrag" , INTERACTION_GROUP , QVariant::Bool } , { AutoCopySelectedText , "AutoCopySelectedText" , INTERACTION_GROUP , QVariant::Bool } + , { TrimTrailingSpacesInSelectedText , "TrimTrailingSpacesInSelectedText" , INTERACTION_GROUP , QVariant::Bool } , { PasteFromSelectionEnabled , "PasteFromSelectionEnabled" , INTERACTION_GROUP , QVariant::Bool } , { PasteFromClipboardEnabled , "PasteFromClipboardEnabled" , INTERACTION_GROUP , QVariant::Bool } , { MiddleClickPasteMode, "MiddleClickPasteMode" , INTERACTION_GROUP , QVariant::Int } @@ -173,6 +174,7 @@ FallbackProfile::FallbackProfile() setProperty(OpenLinksByDirectClickEnabled, false); setProperty(CtrlRequiredForDrag, true); setProperty(AutoCopySelectedText, false); + setProperty(TrimTrailingSpacesInSelectedText, false); setProperty(PasteFromSelectionEnabled, true); setProperty(PasteFromClipboardEnabled, false); setProperty(MiddleClickPasteMode, Enum::PasteFromX11Selection); diff --git a/src/Profile.h b/src/Profile.h index 4756f900f..f14d3a212 100644 --- a/src/Profile.h +++ b/src/Profile.h @@ -205,6 +205,8 @@ public: CtrlRequiredForDrag, /** (bool) If true, automatically copy selected text into the clipboard */ AutoCopySelectedText, + /** (bool) If true, trailing spaces are trimmed in selected text */ + TrimTrailingSpacesInSelectedText, /** (bool) If true, middle mouse button pastes from X Selection */ PasteFromSelectionEnabled, /** (bool) If true, middle mouse button pastes from Clipboard */ diff --git a/src/Screen.cpp b/src/Screen.cpp index cc29cf6b4..816affe71 100644 --- a/src/Screen.cpp +++ b/src/Screen.cpp @@ -1096,22 +1096,22 @@ bool Screen::isSelected(const int x, const int y) const return pos >= _selTopLeft && pos <= _selBottomRight && columnInSelection; } -QString Screen::selectedText(bool preserveLineBreaks) const +QString Screen::selectedText(bool preserveLineBreaks, bool trimTrailingSpaces) const { if (!isSelectionValid()) return QString(); - return text(_selTopLeft, _selBottomRight, preserveLineBreaks); + return text(_selTopLeft, _selBottomRight, preserveLineBreaks, trimTrailingSpaces); } -QString Screen::text(int startIndex, int endIndex, bool preserveLineBreaks) const +QString Screen::text(int startIndex, int endIndex, bool preserveLineBreaks, bool trimTrailingSpaces) const { QString result; QTextStream stream(&result, QIODevice::ReadWrite); PlainTextDecoder decoder; decoder.begin(&stream); - writeToStream(&decoder, startIndex, endIndex, preserveLineBreaks); + writeToStream(&decoder, startIndex, endIndex, preserveLineBreaks, trimTrailingSpaces); decoder.end(); return result; @@ -1123,16 +1123,18 @@ bool Screen::isSelectionValid() const } void Screen::writeSelectionToStream(TerminalCharacterDecoder* decoder , - bool preserveLineBreaks) const + bool preserveLineBreaks, + bool trimTrailingSpaces) const { if (!isSelectionValid()) return; - writeToStream(decoder, _selTopLeft, _selBottomRight, preserveLineBreaks); + writeToStream(decoder, _selTopLeft, _selBottomRight, preserveLineBreaks, trimTrailingSpaces); } void Screen::writeToStream(TerminalCharacterDecoder* decoder, int startIndex, int endIndex, - bool preserveLineBreaks) const + bool preserveLineBreaks, + bool trimTrailingSpaces) const { const int top = startIndex / _columns; const int left = startIndex % _columns; @@ -1155,7 +1157,8 @@ void Screen::writeToStream(TerminalCharacterDecoder* decoder, count, decoder, appendNewLine, - preserveLineBreaks); + preserveLineBreaks, + trimTrailingSpaces); // if the selection goes beyond the end of the last line then // append a new line character. @@ -1175,7 +1178,8 @@ int Screen::copyLineToStream(int line , int count, TerminalCharacterDecoder* decoder, bool appendNewLine, - bool preserveLineBreaks) const + bool preserveLineBreaks, + bool trimTrailingSpaces) const { //buffer to hold characters for decoding //the buffer is static to avoid initialising every @@ -1222,7 +1226,20 @@ int Screen::copyLineToStream(int line , const int screenLine = line - _history->getLines(); Character* data = _screenLines[screenLine].data(); - const int length = _screenLines[screenLine].count(); + int length = _screenLines[screenLine].count(); + + // Don't remove end spaces in lines that wrap + if (trimTrailingSpaces && !(_lineProperties[screenLine] & LINE_WRAPPED)) + { + // ignore trailing white space at the end of the line + for (int i = length-1; i >= 0; i--) + { + if (data[i].character == ' ') + length--; + else + break; + } + } //retrieve line from screen image for (int i = start; i < qMin(start + count, length); i++) { diff --git a/src/Screen.h b/src/Screen.h index b962dea1e..8520438e8 100644 --- a/src/Screen.h +++ b/src/Screen.h @@ -444,15 +444,19 @@ public: * Convenience method. Returns the currently selected text. * @param preserveLineBreaks Specifies whether new line characters should * be inserted into the returned text at the end of each terminal line. + * @param trimTrailingSpaces Specifies whether trailing spaces should be + * trimmed in the returned text. */ - QString selectedText(bool preserveLineBreaks) const; + QString selectedText(bool preserveLineBreaks, bool trimTrailingSpaces = false) const; /** * Convenience method. Returns the text from @p startIndex to @p endIndex. * @param preserveLineBreaks Specifies whether new line characters should * be inserted into the returned text at the end of each terminal line. + * @param trimTrailingSpaces Specifies whether trailing spaces should be + * trimmed in the returned text. */ - QString text(int startIndex, int endIndex, bool preserveLineBreaks) const; + QString text(int startIndex, int endIndex, bool preserveLineBreaks, bool trimTrailingSpaces = false) const; /** * Copies part of the output to a stream. @@ -470,11 +474,12 @@ public: * @param decoder A decoder which converts terminal characters into text. * PlainTextDecoder is the most commonly used decoder which converts characters * into plain text with no formatting. - * @param preserveLineBreaks Specifies whether new line characters should - * be inserted into the returned text at the end of each terminal line. + * @param trimTrailingSpaces Specifies whether trailing spaces should be + * trimmed in the returned text. */ void writeSelectionToStream(TerminalCharacterDecoder* decoder , bool - preserveLineBreaks = true) const; + preserveLineBreaks = true, + bool trimTrailingSpaces = false) const; /** * Checks if the text between from and to is inside the current @@ -593,7 +598,8 @@ private: int count, TerminalCharacterDecoder* decoder, bool appendNewLine, - bool preserveLineBreaks) const; + bool preserveLineBreaks, + bool trimTrailingSpaces) const; //fills a section of the screen image with the character 'c' //the parameters are specified as offsets from the start of the screen image. @@ -625,7 +631,7 @@ private: // copies text from 'startIndex' to 'endIndex' to a stream // startIndex and endIndex are positions generated using the loc(x,y) macro void writeToStream(TerminalCharacterDecoder* decoder, int startIndex, - int endIndex, bool preserveLineBreaks = true) const; + int endIndex, bool preserveLineBreaks = true, bool trimTrailingSpaces = false) const; // copies 'count' lines from the screen buffer into 'dest', // starting from 'startLine', where 0 is the first line in the screen buffer void copyFromScreen(Character* dest, int startLine, int count) const; diff --git a/src/ScreenWindow.cpp b/src/ScreenWindow.cpp index 3c55a297b..bafc6a044 100644 --- a/src/ScreenWindow.cpp +++ b/src/ScreenWindow.cpp @@ -117,9 +117,9 @@ QVector ScreenWindow::getLineProperties() return result; } -QString ScreenWindow::selectedText(bool preserveLineBreaks) const +QString ScreenWindow::selectedText(bool preserveLineBreaks, bool trimTrailingSpaces) const { - return _screen->selectedText(preserveLineBreaks); + return _screen->selectedText(preserveLineBreaks, trimTrailingSpaces); } void ScreenWindow::getSelectionStart(int& column , int& line) diff --git a/src/ScreenWindow.h b/src/ScreenWindow.h index adf6182ac..1aa938a0a 100644 --- a/src/ScreenWindow.h +++ b/src/ScreenWindow.h @@ -222,8 +222,9 @@ public: * Returns the text which is currently selected. * * @param preserveLineBreaks See Screen::selectedText() + * @param trimTrailingSpaces See Screen::selectedText() */ - QString selectedText(bool preserveLineBreaks) const; + QString selectedText(bool preserveLineBreaks, bool trimTrailingSpaces = false) const; public slots: /** diff --git a/src/TerminalDisplay.cpp b/src/TerminalDisplay.cpp index e20bb11fa..d8eac98cb 100644 --- a/src/TerminalDisplay.cpp +++ b/src/TerminalDisplay.cpp @@ -335,6 +335,7 @@ TerminalDisplay::TerminalDisplay(QWidget* parent) , _antialiasText(true) , _printerFriendly(false) , _sessionController(0) + , _trimTrailingSpaces(false) { // terminal applications are not designed with Right-To-Left in mind, // so the layout is forced to Left-To-Right @@ -2590,7 +2591,7 @@ void TerminalDisplay::copyToX11Selection() if (!_screenWindow) return; - QString text = _screenWindow->selectedText(_preserveLineBreaks); + QString text = _screenWindow->selectedText(_preserveLineBreaks, _trimTrailingSpaces); if (text.isEmpty()) return; @@ -2605,7 +2606,7 @@ void TerminalDisplay::copyToClipboard() if (!_screenWindow) return; - QString text = _screenWindow->selectedText(_preserveLineBreaks); + QString text = _screenWindow->selectedText(_preserveLineBreaks, _trimTrailingSpaces); if (text.isEmpty()) return; diff --git a/src/TerminalDisplay.h b/src/TerminalDisplay.h index e1bb91fb4..8e246b84a 100644 --- a/src/TerminalDisplay.h +++ b/src/TerminalDisplay.h @@ -196,6 +196,19 @@ public: return _openLinksByDirectClick; } + /** + * Sets whether trailing spaces should be trimmed in selected text. + */ + void setTrimTrailingSpaces(bool enabled) { + _trimTrailingSpaces = enabled; + } + + /** + * Returns true if trailing spaces should be trimmed in selected text. + */ + bool trimTrailingSpaces() const { + return _trimTrailingSpaces; + } void setLineSpacing(uint); uint lineSpacing() const; @@ -841,6 +854,9 @@ private: static const int DEFAULT_TOP_MARGIN = 1; SessionController* _sessionController; + + bool _trimTrailingSpaces; // trim trailing spaces in selected text + friend class TerminalDisplayAccessible; }; diff --git a/src/ViewManager.cpp b/src/ViewManager.cpp index a2ebe065b..faa139576 100644 --- a/src/ViewManager.cpp +++ b/src/ViewManager.cpp @@ -806,6 +806,7 @@ void ViewManager::applyProfileToView(TerminalDisplay* view , const Profile::Ptr view->setControlDrag(profile->property(Profile::CtrlRequiredForDrag)); view->setBidiEnabled(profile->bidiRenderingEnabled()); view->setLineSpacing(profile->lineSpacing()); + view->setTrimTrailingSpaces(profile->property(Profile::TrimTrailingSpacesInSelectedText)); view->setOpenLinksByDirectClick(profile->property(Profile::OpenLinksByDirectClickEnabled));