diff --git a/src/EditProfileDialog.h b/EditProfileDialog.h
--- a/src/EditProfileDialog.h
+++ b/EditProfileDialog.h
@@ -161,6 +161,7 @@
void toggleDropUrlsAsText(bool);
void toggleCopyTextToClipboard(bool);
void toggleTrimTrailingSpacesInSelectedText(bool);
+ void toggleTrimLeadingSpacesInSelectedText(bool);
void pasteFromX11Selection();
void pasteFromClipboard();
diff --git a/src/EditProfileDialog.cpp b/EditProfileDialog.cpp
--- a/src/EditProfileDialog.cpp
+++ b/EditProfileDialog.cpp
@@ -1160,6 +1160,10 @@
_ui->trimTrailingSpacesButton, Profile::TrimTrailingSpacesInSelectedText,
SLOT(toggleTrimTrailingSpacesInSelectedText(bool))
},
+ {
+ _ui->trimLeadingSpacesButton, Profile::TrimLeadingSpacesInSelectedText,
+ SLOT(toggleTrimLeadingSpacesInSelectedText(bool))
+ },
{
_ui->openLinksByDirectClickButton, Profile::OpenLinksByDirectClickEnabled,
SLOT(toggleOpenLinksByDirectClick(bool))
@@ -1356,6 +1360,11 @@
updateTempProfileProperty(Profile::TrimTrailingSpacesInSelectedText, enable);
}
+void EditProfileDialog::toggleTrimLeadingSpacesInSelectedText(bool enable)
+{
+ updateTempProfileProperty(Profile::TrimLeadingSpacesInSelectedText, enable);
+}
+
void EditProfileDialog::pasteFromX11Selection()
{
updateTempProfileProperty(Profile::MiddleClickPasteMode, Enum::PasteFromX11Selection);
diff --git a/src/EditProfileDialog.ui b/EditProfileDialog.ui
--- a/src/EditProfileDialog.ui
+++ b/EditProfileDialog.ui
@@ -935,6 +935,16 @@
+ -
+
+
+ Trim leading spaces in selected text, useful in some instances
+
+
+ Trim leading spaces
+
+
+
-
diff --git a/src/Emulation.cpp b/Emulation.cpp
--- a/src/Emulation.cpp
+++ b/Emulation.cpp
@@ -100,7 +100,7 @@
void Emulation::checkSelectedText()
{
- QString text = _currentScreen->selectedText(true);
+ QString text = _currentScreen->selectedText(true, false, false, false);
emit selectionChanged(text);
}
diff --git a/src/Filter.cpp b/Filter.cpp
--- a/src/Filter.cpp
+++ b/Filter.cpp
@@ -143,6 +143,7 @@
PlainTextDecoder decoder;
decoder.setTrailingWhitespace(false);
+ decoder.setLeadingWhitespace(false);
// setup new shared buffers for the filters to process on
auto newBuffer = new QString();
diff --git a/src/Profile.h b/Profile.h
--- a/src/Profile.h
+++ b/Profile.h
@@ -207,6 +207,8 @@
AutoCopySelectedText,
/** (bool) If true, trailing spaces are trimmed in selected text */
TrimTrailingSpacesInSelectedText,
+ /** (bool) If true, leading spaces are trimmed in selected text */
+ TrimLeadingSpacesInSelectedText,
/** (bool) If true, then dropped URLs will be pasted as text without asking */
DropUrlsAsText,
/** (bool) If true, middle mouse button pastes from X Selection */
diff --git a/src/Profile.cpp b/Profile.cpp
--- a/src/Profile.cpp
+++ b/Profile.cpp
@@ -115,6 +115,7 @@
, { DropUrlsAsText , "DropUrlsAsText" , INTERACTION_GROUP , QVariant::Bool }
, { AutoCopySelectedText , "AutoCopySelectedText" , INTERACTION_GROUP , QVariant::Bool }
, { TrimTrailingSpacesInSelectedText , "TrimTrailingSpacesInSelectedText" , INTERACTION_GROUP , QVariant::Bool }
+ , { TrimLeadingSpacesInSelectedText , "TrimLeadingSpacesInSelectedText" , INTERACTION_GROUP , QVariant::Bool }
, { PasteFromSelectionEnabled , "PasteFromSelectionEnabled" , INTERACTION_GROUP , QVariant::Bool }
, { PasteFromClipboardEnabled , "PasteFromClipboardEnabled" , INTERACTION_GROUP , QVariant::Bool }
, { MiddleClickPasteMode, "MiddleClickPasteMode" , INTERACTION_GROUP , QVariant::Int }
@@ -188,6 +189,7 @@
setProperty(CtrlRequiredForDrag, true);
setProperty(AutoCopySelectedText, false);
setProperty(TrimTrailingSpacesInSelectedText, false);
+ setProperty(TrimLeadingSpacesInSelectedText, false);
setProperty(DropUrlsAsText, false);
setProperty(PasteFromSelectionEnabled, true);
setProperty(PasteFromClipboardEnabled, false);
diff --git a/src/Screen.h b/Screen.h
--- a/src/Screen.h
+++ b/Screen.h
@@ -443,10 +443,13 @@
* 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(bool preserveLineBreaks,
+ bool trimTrailingSpaces, bool trimLeadingSpaces,
+ bool html) const;
/**
* Convenience method. Returns the text between two indices.
@@ -456,10 +459,13 @@
* 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;
+ bool trimTrailingSpaces, bool trimLeadingSpaces,
+ bool html) const;
/**
* Copies part of the output to a stream.
@@ -481,9 +487,12 @@
* 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;
+ preserveLineBreaks,
+ bool trimTrailingSpaces, bool trimLeadingSpaces) const;
/**
* Checks if the text between from and to is inside the current
@@ -602,7 +611,7 @@
//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 trimTrailingSpaces, bool trimLeadingSpaces) 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 +643,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;
+ bool preserveLineBreaks, bool trimTrailingSpaces, bool trimLeadingSpaces) 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/Screen.cpp b/Screen.cpp
--- a/src/Screen.cpp
+++ b/Screen.cpp
@@ -1087,15 +1087,15 @@
return pos >= _selTopLeft && pos <= _selBottomRight && columnInSelection;
}
-QString Screen::selectedText(bool preserveLineBreaks, bool trimTrailingSpaces, bool html) const
+QString Screen::selectedText(bool preserveLineBreaks, bool trimTrailingSpaces, bool trimLeadingSpaces, bool html) const
{
if (!isSelectionValid())
return QString();
- return text(_selTopLeft, _selBottomRight, preserveLineBreaks, trimTrailingSpaces, html);
+ return text(_selTopLeft, _selBottomRight, preserveLineBreaks, trimTrailingSpaces, trimLeadingSpaces, html);
}
-QString Screen::text(int startIndex, int endIndex, bool preserveLineBreaks, bool trimTrailingSpaces, bool html) const
+QString Screen::text(int startIndex, int endIndex, bool preserveLineBreaks, bool trimTrailingSpaces, bool trimLeadingSpaces, bool html) const
{
QString result;
QTextStream stream(&result, QIODevice::ReadWrite);
@@ -1114,7 +1114,7 @@
}
decoder->begin(&stream);
- writeToStream(decoder, startIndex, endIndex, preserveLineBreaks, trimTrailingSpaces);
+ writeToStream(decoder, startIndex, endIndex, preserveLineBreaks, trimTrailingSpaces, trimLeadingSpaces);
decoder->end();
return result;
@@ -1127,17 +1127,17 @@
void Screen::writeSelectionToStream(TerminalCharacterDecoder* decoder ,
bool preserveLineBreaks,
- bool trimTrailingSpaces) const
+ bool trimTrailingSpaces, bool trimLeadingSpaces) const
{
if (!isSelectionValid())
return;
- writeToStream(decoder, _selTopLeft, _selBottomRight, preserveLineBreaks, trimTrailingSpaces);
+ writeToStream(decoder, _selTopLeft, _selBottomRight, preserveLineBreaks, trimTrailingSpaces, trimLeadingSpaces);
}
void Screen::writeToStream(TerminalCharacterDecoder* decoder,
int startIndex, int endIndex,
bool preserveLineBreaks,
- bool trimTrailingSpaces) const
+ bool trimTrailingSpaces, bool trimLeadingSpaces) const
{
const int top = startIndex / _columns;
const int left = startIndex % _columns;
@@ -1161,7 +1161,8 @@
decoder,
appendNewLine,
preserveLineBreaks,
- trimTrailingSpaces);
+ trimTrailingSpaces,
+ trimLeadingSpaces);
// if the selection goes beyond the end of the last line then
// append a new line character.
@@ -1183,7 +1184,8 @@
TerminalCharacterDecoder* decoder,
bool appendNewLine,
bool preserveLineBreaks,
- bool trimTrailingSpaces) const
+ bool trimTrailingSpaces,
+ bool trimLeadingSpaces) const
{
//buffer to hold characters for decoding
//the buffer is static to avoid initializing every
@@ -1275,6 +1277,25 @@
}
}
+ if (trimLeadingSpaces) {
+ 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 +1305,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), true, false, false);
}
void Screen::addHistLine()
diff --git a/src/ScreenWindow.h b/ScreenWindow.h
--- a/src/ScreenWindow.h
+++ b/ScreenWindow.h
@@ -229,10 +229,12 @@
*
* @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(bool preserveLineBreaks,
+ bool trimTrailingSpaces, bool trimLeadingSpaces,
+ bool html) const;
public Q_SLOTS:
/**
diff --git a/src/ScreenWindow.cpp b/ScreenWindow.cpp
--- a/src/ScreenWindow.cpp
+++ b/ScreenWindow.cpp
@@ -125,10 +125,11 @@
return result;
}
-QString ScreenWindow::selectedText(bool preserveLineBreaks, bool trimTrailingSpaces,
+QString ScreenWindow::selectedText(bool preserveLineBreaks,
+ bool trimTrailingSpaces, bool trimLeadingSpaces,
bool html) const
{
- return _screen->selectedText(preserveLineBreaks, trimTrailingSpaces, html);
+ return _screen->selectedText(preserveLineBreaks, trimTrailingSpaces, trimLeadingSpaces, html);
}
void ScreenWindow::getSelectionStart(int &column, int &line)
diff --git a/src/SessionController.cpp b/SessionController.cpp
--- a/src/SessionController.cpp
+++ b/SessionController.cpp
@@ -1148,7 +1148,7 @@
void SessionController::searchBarEvent()
{
- QString selectedText = _view->screenWindow()->selectedText(true, true);
+ QString selectedText = _view->screenWindow()->selectedText(true, true, true, false);
if (!selectedText.isEmpty())
_searchBar->setSearchText(selectedText);
diff --git a/src/TerminalCharacterDecoder.h b/TerminalCharacterDecoder.h
--- a/src/TerminalCharacterDecoder.h
+++ b/TerminalCharacterDecoder.h
@@ -85,6 +85,17 @@
* in the output.
*/
bool trailingWhitespace() const;
+ /**
+ * 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;
/**
* Returns of character positions in the output stream
* at which new lines where added. Returns an empty if setTrackLinePositions() is false or if
@@ -103,6 +114,7 @@
private:
QTextStream *_output;
bool _includeTrailingWhitespace;
+ bool _includeLeadingWhitespace;
bool _recordLinePositions;
QList _linePositions;
diff --git a/src/TerminalCharacterDecoder.cpp b/TerminalCharacterDecoder.cpp
--- a/src/TerminalCharacterDecoder.cpp
+++ b/TerminalCharacterDecoder.cpp
@@ -34,6 +34,7 @@
PlainTextDecoder::PlainTextDecoder()
: _output(nullptr)
, _includeTrailingWhitespace(true)
+ , _includeLeadingWhitespace(true)
, _recordLinePositions(false)
{
}
@@ -45,6 +46,14 @@
{
return _includeTrailingWhitespace;
}
+void PlainTextDecoder::setLeadingWhitespace(bool enable)
+{
+ _includeLeadingWhitespace = enable;
+}
+bool PlainTextDecoder::leadingWhitespace() const
+{
+ return _includeLeadingWhitespace;
+}
void PlainTextDecoder::begin(QTextStream* output)
{
_output = output;
@@ -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/TerminalDisplay.h
--- a/src/TerminalDisplay.h
+++ b/TerminalDisplay.h
@@ -223,6 +223,22 @@
return _trimTrailingSpaces;
}
+ /**
+ * 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;
+ }
+
void setLineSpacing(uint);
uint lineSpacing() const;
@@ -971,6 +987,7 @@
SessionController *_sessionController;
bool _trimTrailingSpaces; // trim trailing spaces in selected text
+ bool _trimLeadingSpaces; // trim leading spaces in selected text
bool _mouseWheelZoom; // enable mouse wheel zooming or not
int _margin; // the contents margin
diff --git a/src/TerminalDisplay.cpp b/TerminalDisplay.cpp
--- a/src/TerminalDisplay.cpp
+++ b/TerminalDisplay.cpp
@@ -378,6 +378,7 @@
, _printerFriendly(false)
, _sessionController(nullptr)
, _trimTrailingSpaces(false)
+ , _trimLeadingSpaces(false)
, _margin(1)
, _centerContents(false)
, _opacity(1.0)
@@ -2893,10 +2894,10 @@
if (_screenWindow == nullptr)
return;
- QString text = _screenWindow->selectedText(_preserveLineBreaks, _trimTrailingSpaces);
+ QString text = _screenWindow->selectedText(_preserveLineBreaks, _trimTrailingSpaces, _trimLeadingSpaces, false);
if (text.isEmpty())
return;
- QString html = _screenWindow->selectedText(_preserveLineBreaks, _trimTrailingSpaces, true);
+ QString html = _screenWindow->selectedText(_preserveLineBreaks, _trimTrailingSpaces, _trimLeadingSpaces, true);
auto mimeData = new QMimeData;
mimeData->setText(text);
@@ -2915,10 +2916,10 @@
if (_screenWindow == nullptr)
return;
- QString text = _screenWindow->selectedText(_preserveLineBreaks, _trimTrailingSpaces);
+ QString text = _screenWindow->selectedText(_preserveLineBreaks, _trimTrailingSpaces, _trimLeadingSpaces, false);
if (text.isEmpty())
return;
- QString html = _screenWindow->selectedText(_preserveLineBreaks, _trimTrailingSpaces, true);
+ QString html = _screenWindow->selectedText(_preserveLineBreaks, _trimTrailingSpaces, _trimLeadingSpaces, true);
auto mimeData = new QMimeData;
mimeData->setText(text);
diff --git a/src/TerminalDisplayAccessible.cpp b/TerminalDisplayAccessible.cpp
--- a/src/TerminalDisplayAccessible.cpp
+++ b/TerminalDisplayAccessible.cpp
@@ -99,7 +99,7 @@
}
return display->screenWindow()->screen()->text(0, display->_usedColumns * display->_usedLines,
- true);
+ true, false, false, false);
}
void TerminalDisplayAccessible::addSelection(int startOffset, int endOffset)
@@ -186,7 +186,7 @@
return QString();
}
- return display()->screenWindow()->screen()->text(startOffset, endOffset, true);
+ return display()->screenWindow()->screen()->text(startOffset, endOffset, true, false, false, false);
}
TerminalDisplay *TerminalDisplayAccessible::display() const
diff --git a/src/ViewManager.cpp b/ViewManager.cpp
--- a/src/ViewManager.cpp
+++ b/ViewManager.cpp
@@ -909,6 +909,7 @@
view->setBidiEnabled(profile->bidiRenderingEnabled());
view->setLineSpacing(profile->lineSpacing());
view->setTrimTrailingSpaces(profile->property(Profile::TrimTrailingSpacesInSelectedText));
+ view->setTrimLeadingSpaces(profile->property(Profile::TrimLeadingSpacesInSelectedText));
view->setOpenLinksByDirectClick(profile->property(Profile::OpenLinksByDirectClickEnabled));