diff --git a/src/EditProfileDialog.h b/src/EditProfileDialog.h
--- a/src/EditProfileDialog.h
+++ b/src/EditProfileDialog.h
@@ -162,6 +162,7 @@
void toggleCtrlRequiredForDrag(bool);
void toggleDropUrlsAsText(bool);
void toggleCopyTextToClipboard(bool);
+ void toggleTrimLeadingSpacesInSelectedText(bool);
void toggleTrimTrailingSpacesInSelectedText(bool);
void pasteFromX11Selection();
void pasteFromClipboard();
diff --git a/src/EditProfileDialog.cpp b/src/EditProfileDialog.cpp
--- a/src/EditProfileDialog.cpp
+++ b/src/EditProfileDialog.cpp
@@ -1228,6 +1228,10 @@
_ui->copyTextToClipboardButton, Profile::AutoCopySelectedText,
SLOT(toggleCopyTextToClipboard(bool))
},
+ {
+ _ui->trimLeadingSpacesButton, Profile::TrimLeadingSpacesInSelectedText,
+ SLOT(toggleTrimLeadingSpacesInSelectedText(bool))
+ },
{
_ui->trimTrailingSpacesButton, Profile::TrimTrailingSpacesInSelectedText,
SLOT(toggleTrimTrailingSpacesInSelectedText(bool))
@@ -1423,6 +1427,11 @@
updateTempProfileProperty(Profile::AutoCopySelectedText, enable);
}
+void EditProfileDialog::toggleTrimLeadingSpacesInSelectedText(bool enable)
+{
+ updateTempProfileProperty(Profile::TrimLeadingSpacesInSelectedText, enable);
+}
+
void EditProfileDialog::toggleTrimTrailingSpacesInSelectedText(bool enable)
{
updateTempProfileProperty(Profile::TrimTrailingSpacesInSelectedText, enable);
diff --git a/src/EditProfileDialog.ui b/src/EditProfileDialog.ui
--- a/src/EditProfileDialog.ui
+++ b/src/EditProfileDialog.ui
@@ -925,6 +925,16 @@
+ -
+
+
+ Trim leading spaces in selected text, useful in some instances
+
+
+ Trim leading spaces
+
+
+
-
diff --git a/src/Emulation.cpp b/src/Emulation.cpp
--- a/src/Emulation.cpp
+++ b/src/Emulation.cpp
@@ -100,7 +100,7 @@
void Emulation::checkSelectedText()
{
- QString text = _currentScreen->selectedText(true);
+ QString text = _currentScreen->selectedText(Screen::PreserveLineBreaks);
emit selectionChanged(text);
}
diff --git a/src/Filter.cpp b/src/Filter.cpp
--- a/src/Filter.cpp
+++ b/src/Filter.cpp
@@ -142,6 +142,7 @@
reset();
PlainTextDecoder decoder;
+ decoder.setLeadingWhitespace(false);
decoder.setTrailingWhitespace(false);
// setup new shared buffers for the filters to process on
diff --git a/src/Profile.h b/src/Profile.h
--- a/src/Profile.h
+++ b/src/Profile.h
@@ -205,6 +205,8 @@
CtrlRequiredForDrag,
/** (bool) If true, automatically copy selected text into the clipboard */
AutoCopySelectedText,
+ /** (bool) If true, leading spaces are trimmed in selected text */
+ TrimLeadingSpacesInSelectedText,
/** (bool) If true, trailing spaces are trimmed in selected text */
TrimTrailingSpacesInSelectedText,
/** (bool) If true, then dropped URLs will be pasted as text without asking */
diff --git a/src/Profile.cpp b/src/Profile.cpp
--- a/src/Profile.cpp
+++ b/src/Profile.cpp
@@ -114,6 +114,7 @@
, { CtrlRequiredForDrag, "CtrlRequiredForDrag" , INTERACTION_GROUP , QVariant::Bool }
, { DropUrlsAsText , "DropUrlsAsText" , INTERACTION_GROUP , QVariant::Bool }
, { AutoCopySelectedText , "AutoCopySelectedText" , INTERACTION_GROUP , QVariant::Bool }
+ , { TrimLeadingSpacesInSelectedText , "TrimLeadingSpacesInSelectedText" , INTERACTION_GROUP , QVariant::Bool }
, { TrimTrailingSpacesInSelectedText , "TrimTrailingSpacesInSelectedText" , INTERACTION_GROUP , QVariant::Bool }
, { PasteFromSelectionEnabled , "PasteFromSelectionEnabled" , INTERACTION_GROUP , QVariant::Bool }
, { PasteFromClipboardEnabled , "PasteFromClipboardEnabled" , INTERACTION_GROUP , QVariant::Bool }
@@ -187,6 +188,7 @@
setProperty(OpenLinksByDirectClickEnabled, false);
setProperty(CtrlRequiredForDrag, true);
setProperty(AutoCopySelectedText, false);
+ setProperty(TrimLeadingSpacesInSelectedText, false);
setProperty(TrimTrailingSpacesInSelectedText, false);
setProperty(DropUrlsAsText, false);
setProperty(PasteFromSelectionEnabled, true);
diff --git a/src/Screen.h b/src/Screen.h
--- a/src/Screen.h
+++ b/src/Screen.h
@@ -73,6 +73,15 @@
class Screen
{
public:
+ enum DecodingOption {
+ PlainText = 0x0,
+ ConvertToHtml = 0x1,
+ PreserveLineBreaks = 0x2,
+ TrimLeadingWhitespace = 0x4,
+ TrimTrailingWhitespace = 0x8
+ };
+ Q_DECLARE_FLAGS(DecodingOptions, DecodingOption)
+
/** Construct a new screen image of size @p lines by @p columns. */
Screen(int lines, int columns);
~Screen();
@@ -443,10 +452,11 @@
* 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.
+ * @param trimLeadingSpaces Specifies whether leading spaces should be
+ * trimmed in the returned text.
* @param html Specifies if returned text should have HTML tags.
*/
- QString selectedText(bool preserveLineBreaks, bool trimTrailingSpaces = false,
- bool html = false) const;
+ QString selectedText(const DecodingOptions options) const;
/**
* Convenience method. Returns the text between two indices.
@@ -456,10 +466,11 @@
* 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.
+ * @param trimLeadingSpaces Specifies whether leading spaces should be
+ * trimmed in the returned text.
* @param html Specifies if returned text should have HTML tags.
*/
- QString text(int startIndex, int endIndex, bool preserveLineBreaks,
- bool trimTrailingSpaces = false, bool html = false) const;
+ QString text(int startIndex, int endIndex, const DecodingOptions options) const;
/**
* Copies part of the output to a stream.
@@ -481,9 +492,10 @@
* 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.
+ * @param trimLeadingSpaces Specifies whether leading spaces should be
+ * trimmed in the returned text.
*/
- void writeSelectionToStream(TerminalCharacterDecoder *decoder, bool
- preserveLineBreaks = true, bool trimTrailingSpaces = false) const;
+ void writeSelectionToStream(TerminalCharacterDecoder *decoder, const Konsole::Screen::DecodingOptions options) const;
/**
* Checks if the text between from and to is inside the current
@@ -601,8 +613,7 @@
//decoder - a decoder which converts terminal characters (an Character array) into text
//appendNewLine - if true a new line character (\n) is appended to the end of the line
int copyLineToStream(int line, int start, int count, TerminalCharacterDecoder *decoder,
- bool appendNewLine, bool preserveLineBreaks,
- bool trimTrailingSpaces) const;
+ bool appendNewLine, const Konsole::Screen::DecodingOptions options) 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.
@@ -634,7 +645,7 @@
// 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, bool trimTrailingSpaces = false) const;
+ const Konsole::Screen::DecodingOptions options) 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;
@@ -715,6 +726,10 @@
// last position where we added a character
int _lastPos;
};
+
}
+Q_DECLARE_OPERATORS_FOR_FLAGS(Konsole::Screen::DecodingOptions)
+
+
#endif // SCREEN_H
diff --git a/src/Screen.cpp b/src/Screen.cpp
--- a/src/Screen.cpp
+++ b/src/Screen.cpp
@@ -1087,24 +1087,24 @@
return pos >= _selTopLeft && pos <= _selBottomRight && columnInSelection;
}
-QString Screen::selectedText(bool preserveLineBreaks, bool trimTrailingSpaces, bool html) const
+QString Screen::selectedText(const DecodingOptions options) const
{
if (!isSelectionValid())
return QString();
- return text(_selTopLeft, _selBottomRight, preserveLineBreaks, trimTrailingSpaces, html);
+ return text(_selTopLeft, _selBottomRight, options);
}
-QString Screen::text(int startIndex, int endIndex, bool preserveLineBreaks, bool trimTrailingSpaces, bool html) const
+QString Screen::text(int startIndex, int endIndex, const DecodingOptions options) const
{
QString result;
QTextStream stream(&result, QIODevice::ReadWrite);
HTMLDecoder htmlDecoder;
PlainTextDecoder plainTextDecoder;
TerminalCharacterDecoder *decoder;
- if(html)
+ if(options & ConvertToHtml)
{
decoder = &htmlDecoder;
}
@@ -1114,7 +1114,7 @@
}
decoder->begin(&stream);
- writeToStream(decoder, startIndex, endIndex, preserveLineBreaks, trimTrailingSpaces);
+ writeToStream(decoder, startIndex, endIndex, options);
decoder->end();
return result;
@@ -1126,18 +1126,16 @@
}
void Screen::writeSelectionToStream(TerminalCharacterDecoder* decoder ,
- bool preserveLineBreaks,
- bool trimTrailingSpaces) const
+ const DecodingOptions options) const
{
if (!isSelectionValid())
return;
- writeToStream(decoder, _selTopLeft, _selBottomRight, preserveLineBreaks, trimTrailingSpaces);
+ writeToStream(decoder, _selTopLeft, _selBottomRight, options);
}
void Screen::writeToStream(TerminalCharacterDecoder* decoder,
int startIndex, int endIndex,
- bool preserveLineBreaks,
- bool trimTrailingSpaces) const
+ const DecodingOptions options) const
{
const int top = startIndex / _columns;
const int left = startIndex % _columns;
@@ -1160,17 +1158,16 @@
count,
decoder,
appendNewLine,
- preserveLineBreaks,
- trimTrailingSpaces);
+ options);
// if the selection goes beyond the end of the last line then
// append a new line character.
//
// this makes it possible to 'select' a trailing new line character after
// the text on a line.
if (y == bottom &&
copied < count &&
- !trimTrailingSpaces) {
+ !options.testFlag(TrimTrailingWhitespace)) {
Character newLineChar('\n');
decoder->decodeLine(&newLineChar, 1, 0);
}
@@ -1182,8 +1179,7 @@
int count,
TerminalCharacterDecoder* decoder,
bool appendNewLine,
- bool preserveLineBreaks,
- bool trimTrailingSpaces) const
+ const DecodingOptions options) const
{
//buffer to hold characters for decoding
//the buffer is static to avoid initializing every
@@ -1239,7 +1235,7 @@
int length = _screenLines[screenLine].count();
// Don't remove end spaces in lines that wrap
- if (trimTrailingSpaces && ((_lineProperties[screenLine] & LINE_WRAPPED) == 0))
+ if (options.testFlag(TrimTrailingWhitespace) && ((_lineProperties[screenLine] & LINE_WRAPPED) == 0))
{
// ignore trailing white space at the end of the line
for (int i = length-1; i >= 0; i--)
@@ -1270,11 +1266,30 @@
// When users ask not to preserve the linebreaks, they usually mean:
// `treat LINEBREAK as SPACE, thus joining multiple _lines into
// single line in the same way as 'J' does in VIM.`
- characterBuffer[count] = preserveLineBreaks ? Character('\n') : Character(' ');
+ characterBuffer[count] = options.testFlag(PreserveLineBreaks) ? Character('\n') : Character(' ');
count++;
}
}
+ if (options & TrimLeadingWhitespace) {
+ int spacesCount = 0;
+ for (spacesCount = 0; spacesCount < count; spacesCount++) {
+ if (!QChar(characterBuffer[spacesCount].character).isSpace()) {
+ break;
+ }
+ }
+
+ if (spacesCount >= count) {
+ return 0;
+ }
+
+ for (int i=0; i < count - spacesCount; i++) {
+ characterBuffer[i] = characterBuffer[i + spacesCount];
+ }
+
+ count -= spacesCount;
+ }
+
//decode line and write to text stream
decoder->decodeLine((Character*) characterBuffer ,
count, currentLineProperties);
@@ -1284,7 +1299,7 @@
void Screen::writeLinesToStream(TerminalCharacterDecoder* decoder, int fromLine, int toLine) const
{
- writeToStream(decoder, loc(0, fromLine), loc(_columns - 1, toLine));
+ writeToStream(decoder, loc(0, fromLine), loc(_columns - 1, toLine), PreserveLineBreaks);
}
void Screen::addHistLine()
diff --git a/src/ScreenWindow.h b/src/ScreenWindow.h
--- a/src/ScreenWindow.h
+++ b/src/ScreenWindow.h
@@ -27,9 +27,9 @@
// Konsole
#include "Character.h"
+#include "Screen.h"
namespace Konsole {
-class Screen;
/**
* Provides a window onto a section of a terminal screen. A terminal widget can then render
@@ -229,10 +229,10 @@
*
* @param preserveLineBreaks See Screen::selectedText()
* @param trimTrailingSpaces See Screen::selectedText()
+ * @param trimLeadingSpaces See Screen::selectedText()
* @param html Specifies if returned text should have HTML tags.
*/
- QString selectedText(bool preserveLineBreaks, bool trimTrailingSpaces = false,
- bool html = false) const;
+ QString selectedText(const Konsole::Screen::DecodingOptions options) const;
public Q_SLOTS:
/**
diff --git a/src/ScreenWindow.cpp b/src/ScreenWindow.cpp
--- a/src/ScreenWindow.cpp
+++ b/src/ScreenWindow.cpp
@@ -125,10 +125,9 @@
return result;
}
-QString ScreenWindow::selectedText(bool preserveLineBreaks, bool trimTrailingSpaces,
- bool html) const
+QString ScreenWindow::selectedText(const Screen::DecodingOptions options) const
{
- return _screen->selectedText(preserveLineBreaks, trimTrailingSpaces, html);
+ return _screen->selectedText(options);
}
void ScreenWindow::getSelectionStart(int &column, int &line)
diff --git a/src/SessionController.cpp b/src/SessionController.cpp
--- a/src/SessionController.cpp
+++ b/src/SessionController.cpp
@@ -1148,7 +1148,7 @@
void SessionController::searchBarEvent()
{
- QString selectedText = _view->screenWindow()->selectedText(true, true);
+ QString selectedText = _view->screenWindow()->selectedText(Screen::PreserveLineBreaks | Screen::TrimLeadingWhitespace | Screen::TrimTrailingWhitespace);
if (!selectedText.isEmpty())
_searchBar->setSearchText(selectedText);
diff --git a/src/TerminalCharacterDecoder.h b/src/TerminalCharacterDecoder.h
--- a/src/TerminalCharacterDecoder.h
+++ b/src/TerminalCharacterDecoder.h
@@ -74,6 +74,17 @@
public:
PlainTextDecoder();
+ /**
+ * Set whether leading whitespace at the end of lines should be included
+ * in the output.
+ * Defaults to true.
+ */
+ void setLeadingWhitespace(bool enable);
+ /**
+ * Returns whether leading whitespace at the end of lines is included
+ * in the output.
+ */
+ bool leadingWhitespace() const;
/**
* Set whether trailing whitespace at the end of lines should be included
* in the output.
@@ -102,6 +113,7 @@
private:
QTextStream *_output;
+ bool _includeLeadingWhitespace;
bool _includeTrailingWhitespace;
bool _recordLinePositions;
diff --git a/src/TerminalCharacterDecoder.cpp b/src/TerminalCharacterDecoder.cpp
--- a/src/TerminalCharacterDecoder.cpp
+++ b/src/TerminalCharacterDecoder.cpp
@@ -33,10 +33,19 @@
using namespace Konsole;
PlainTextDecoder::PlainTextDecoder()
: _output(nullptr)
+ , _includeLeadingWhitespace(true)
, _includeTrailingWhitespace(true)
, _recordLinePositions(false)
{
}
+void PlainTextDecoder::setLeadingWhitespace(bool enable)
+{
+ _includeLeadingWhitespace = enable;
+}
+bool PlainTextDecoder::leadingWhitespace() const
+{
+ return _includeLeadingWhitespace;
+}
void PlainTextDecoder::setTrailingWhitespace(bool enable)
{
_includeTrailingWhitespace = enable;
@@ -82,12 +91,26 @@
QString plainText;
plainText.reserve(count);
- int outputCount = count;
+ // If we should remove leading whitespace find the first non-space character
+ int start = 0;
+ if (!_includeLeadingWhitespace) {
+ for (start = 0; start < count; start++) {
+ if (!characters[start].isSpace()) {
+ break;
+ }
+ }
+ }
+
+ int outputCount = count - start;
+
+ if (outputCount <= 0) {
+ return;
+ }
// if inclusion of trailing whitespace is disabled then find the end of the
// line
if (!_includeTrailingWhitespace) {
- for (int i = count - 1 ; i >= 0 ; i--) {
+ for (int i = count - 1 ; i >= start ; i--) {
if (!characters[i].isSpace())
break;
else
@@ -97,7 +120,7 @@
// find out the last technically real character in the line
int realCharacterGuard = -1;
- for (int i = count - 1 ; i >= 0 ; i--) {
+ for (int i = count - 1 ; i >= start ; i--) {
// FIXME: the special case of '\n' here is really ugly
// Maybe the '\n' should be added after calling this method in
// Screen::copyLineToStream()
@@ -107,7 +130,7 @@
}
}
- for (int i = 0; i < outputCount;) {
+ for (int i = start; i < outputCount;) {
if ((characters[i].rendition & RE_EXTENDED_CHAR) != 0) {
ushort extendedCharLength = 0;
const ushort* chars = ExtendedCharTable::instance.lookupExtendedChar(characters[i].character, extendedCharLength);
diff --git a/src/TerminalDisplay.h b/src/TerminalDisplay.h
--- a/src/TerminalDisplay.h
+++ b/src/TerminalDisplay.h
@@ -207,6 +207,22 @@
return _openLinksByDirectClick;
}
+ /**
+ * Sets whether leading spaces should be trimmed in selected text.
+ */
+ void setTrimLeadingSpaces(bool enabled)
+ {
+ _trimLeadingSpaces = enabled;
+ }
+
+ /**
+ * Returns true if leading spaces should be trimmed in selected text.
+ */
+ bool trimLeadingSpaces() const
+ {
+ return _trimLeadingSpaces;
+ }
+
/**
* Sets whether trailing spaces should be trimmed in selected text.
*/
@@ -841,6 +857,9 @@
QPoint findWordStart(const QPoint &pnt);
QPoint findWordEnd(const QPoint &pnt);
+ // Uses the current settings for trimming whitespace and preserving linebreaks to create a proper flag value for Screen
+ Screen::DecodingOptions currentDecodingOptions();
+
// the window onto the terminal screen which this display
// is currently showing.
QPointer _screenWindow;
@@ -970,6 +989,7 @@
SessionController *_sessionController;
+ bool _trimLeadingSpaces; // trim leading spaces in selected text
bool _trimTrailingSpaces; // trim trailing spaces in selected text
bool _mouseWheelZoom; // enable mouse wheel zooming or not
diff --git a/src/TerminalDisplay.cpp b/src/TerminalDisplay.cpp
--- a/src/TerminalDisplay.cpp
+++ b/src/TerminalDisplay.cpp
@@ -377,6 +377,7 @@
, _useFontLineCharacters(false)
, _printerFriendly(false)
, _sessionController(nullptr)
+ , _trimLeadingSpaces(false)
, _trimTrailingSpaces(false)
, _margin(1)
, _centerContents(false)
@@ -2730,6 +2731,22 @@
return QPoint(x, y);
}
+Screen::DecodingOptions TerminalDisplay::currentDecodingOptions()
+{
+ Screen::DecodingOptions decodingOptions;
+ if (_preserveLineBreaks) {
+ decodingOptions |= Screen::PreserveLineBreaks;
+ }
+ if (_trimLeadingSpaces) {
+ decodingOptions |= Screen::TrimLeadingWhitespace;
+ }
+ if (_trimTrailingSpaces) {
+ decodingOptions |= Screen::TrimTrailingWhitespace;
+ }
+
+ return decodingOptions;
+}
+
void TerminalDisplay::mouseTripleClickEvent(QMouseEvent* ev)
{
if (_screenWindow == nullptr) return;
@@ -2893,10 +2910,11 @@
if (_screenWindow == nullptr)
return;
- QString text = _screenWindow->selectedText(_preserveLineBreaks, _trimTrailingSpaces);
+
+ QString text = _screenWindow->selectedText(currentDecodingOptions());
if (text.isEmpty())
return;
- QString html = _screenWindow->selectedText(_preserveLineBreaks, _trimTrailingSpaces, true);
+ QString html = _screenWindow->selectedText(currentDecodingOptions() | Screen::ConvertToHtml);
auto mimeData = new QMimeData;
mimeData->setText(text);
@@ -2915,10 +2933,10 @@
if (_screenWindow == nullptr)
return;
- QString text = _screenWindow->selectedText(_preserveLineBreaks, _trimTrailingSpaces);
+ QString text = _screenWindow->selectedText(currentDecodingOptions());
if (text.isEmpty())
return;
- QString html = _screenWindow->selectedText(_preserveLineBreaks, _trimTrailingSpaces, true);
+ QString html = _screenWindow->selectedText(currentDecodingOptions() | Screen::ConvertToHtml);
auto mimeData = new QMimeData;
mimeData->setText(text);
diff --git a/src/TerminalDisplayAccessible.cpp b/src/TerminalDisplayAccessible.cpp
--- a/src/TerminalDisplayAccessible.cpp
+++ b/src/TerminalDisplayAccessible.cpp
@@ -98,8 +98,7 @@
return QString();
}
- return display->screenWindow()->screen()->text(0, display->_usedColumns * display->_usedLines,
- true);
+ return display->screenWindow()->screen()->text(0, display->_usedColumns * display->_usedLines, Screen::PreserveLineBreaks);
}
void TerminalDisplayAccessible::addSelection(int startOffset, int endOffset)
@@ -186,7 +185,7 @@
return QString();
}
- return display()->screenWindow()->screen()->text(startOffset, endOffset, true);
+ return display()->screenWindow()->screen()->text(startOffset, endOffset, Screen::PreserveLineBreaks);
}
TerminalDisplay *TerminalDisplayAccessible::display() const
diff --git a/src/ViewManager.cpp b/src/ViewManager.cpp
--- a/src/ViewManager.cpp
+++ b/src/ViewManager.cpp
@@ -913,6 +913,7 @@
view->setDropUrlsAsText(profile->property(Profile::DropUrlsAsText));
view->setBidiEnabled(profile->bidiRenderingEnabled());
view->setLineSpacing(profile->lineSpacing());
+ view->setTrimLeadingSpaces(profile->property(Profile::TrimLeadingSpacesInSelectedText));
view->setTrimTrailingSpaces(profile->property(Profile::TrimTrailingSpacesInSelectedText));
view->setOpenLinksByDirectClick(profile->property(Profile::OpenLinksByDirectClickEnabled));