Improved Single Line Comment
Closes #2031 Improved the Single Line Comment/Uncomment/Toggle behaviour for Lexers with the following condition: Single Line Comment Symbol : false Stream Comment Symbol Start : true Stream Comment Symbol End : true This includes among others: XML, HTML, CSS, Caml, Pascal, ... In the current Npp a 'Single Line Comment' will do a 'Block Comment' and the 'Toggle Single Line Comment' entry does nothing at all for these kind of Lexers. This implementation uses the stream comment symbols (start/end) to accomplish a single line comment, exactly the same way as the usual Single Line Comment/Uncomment/Toggle functionality does for Lexers with a single line symbol. This will add more consistency to the Single Line Comment feature. NOTE The selection range behaviour has been revised to be more accurate and for fixing some 'line leaving' bugs when uncommenting.
This commit is contained in:
parent
1abac15799
commit
7fcc20f84a
@ -3803,19 +3803,29 @@ static generic_string extractSymbol(TCHAR firstChar, TCHAR secondChar, const TCH
|
||||
|
||||
bool Notepad_plus::doBlockComment(comment_mode currCommentMode)
|
||||
{
|
||||
Buffer * buf = _pEditView->getCurrentBuffer();
|
||||
//--FLS: Avoid side-effects (e.g. cursor moves number of comment-characters) when file is read-only.
|
||||
if (buf->isReadOnly())
|
||||
return false;
|
||||
|
||||
//--LS: BlockToStreamComment:
|
||||
const TCHAR *commentStart;
|
||||
const TCHAR *commentEnd;
|
||||
generic_string symbolStart;
|
||||
generic_string symbolEnd;
|
||||
|
||||
const TCHAR *commentLineSybol;
|
||||
const TCHAR *commentLineSymbol;
|
||||
generic_string symbol;
|
||||
|
||||
Buffer * buf = _pEditView->getCurrentBuffer();
|
||||
//--FLS: Avoid side-effects (e.g. cursor moves number of comment-characters) when file is read-only.
|
||||
if (buf->isReadOnly())
|
||||
return false;
|
||||
//Single Line Comment/Uncomment/Toggle can have two modes:
|
||||
// * a NORMAL MODE which uses a commentLineSymbol to comment/uncomment code per line, and
|
||||
// * an ADVANCED MODE which uses commentStart and commentEnd symbols to comment/uncomment code per line.
|
||||
//The NORMAL MODE is used for all Lexers which have a commentLineSymbol defined.
|
||||
//The ADVANCED MODE is only available for Lexers which do not have a commentLineSymbol but commentStreamSymbols (start/end) defined.
|
||||
//The ADVANCED MODE behaves the same way as the NORMAL MODE (comment/uncomment every single line in the selection range separately)
|
||||
//but uses two smbols to accomplish this.
|
||||
bool isSingleLineAdvancedMode = false;
|
||||
|
||||
if (buf->getLangType() == L_USER)
|
||||
{
|
||||
UserLangContainer * userLangContainer = NppParameters::getInstance()->getULCFromName(buf->getUserDefineLangName());
|
||||
@ -3823,7 +3833,7 @@ bool Notepad_plus::doBlockComment(comment_mode currCommentMode)
|
||||
return false;
|
||||
|
||||
symbol = extractSymbol('0', '0', userLangContainer->_keywordLists[SCE_USER_KWLIST_COMMENTS]);
|
||||
commentLineSybol = symbol.c_str();
|
||||
commentLineSymbol = symbol.c_str();
|
||||
//--FLS: BlockToStreamComment: Needed to decide, if stream-comment can be called below!
|
||||
symbolStart = extractSymbol('0', '3', userLangContainer->_keywordLists[SCE_USER_KWLIST_COMMENTS]);
|
||||
commentStart = symbolStart.c_str();
|
||||
@ -3832,24 +3842,35 @@ bool Notepad_plus::doBlockComment(comment_mode currCommentMode)
|
||||
}
|
||||
else
|
||||
{
|
||||
commentLineSybol = buf->getCommentLineSymbol();
|
||||
commentLineSymbol = buf->getCommentLineSymbol();
|
||||
//--FLS: BlockToStreamComment: Needed to decide, if stream-comment can be called below!
|
||||
commentStart = buf->getCommentStart();
|
||||
commentEnd = buf->getCommentEnd();
|
||||
}
|
||||
|
||||
if ((!commentLineSybol) || (!commentLineSybol[0]) || (commentLineSybol == NULL))
|
||||
if ((!commentLineSymbol) || (!commentLineSymbol[0]) || (commentLineSymbol == NULL))
|
||||
{
|
||||
//--FLS: BlockToStreamComment: If there is no block-comment symbol, try the stream comment:
|
||||
if (!(!commentStart || !commentStart[0] || commentStart == NULL || !commentEnd || !commentEnd[0] || commentEnd == NULL))
|
||||
{
|
||||
if ((currCommentMode == cm_comment))
|
||||
if (currCommentMode == cm_comment)
|
||||
{
|
||||
return doStreamComment();
|
||||
//Do an advanced "Single Line Comment" by using stream-comment symbols (start/end) per line in this case.
|
||||
isSingleLineAdvancedMode = true;
|
||||
//return doStreamComment(); //Use "Block Comment" for this.
|
||||
}
|
||||
else if (currCommentMode == cm_uncomment)
|
||||
{
|
||||
//"undoStreamComment()" can be more flexible than "isSingleLineAdvancedMode = true",
|
||||
//since it can uncomment more embedded levels at once and the commentEnd symbol can be located everywhere.
|
||||
//But, depending on the selection start/end position, the first/last selected line may not be uncommented properly!
|
||||
return undoStreamComment();
|
||||
//isSingleLineAdvancedMode = true;
|
||||
}
|
||||
else if (currCommentMode == cm_toggle)
|
||||
{
|
||||
//Do an advanced "Toggle Single Line Comment" by using stream-comment symbols (start/end) per line in this case.
|
||||
isSingleLineAdvancedMode = true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
@ -3858,10 +3879,37 @@ bool Notepad_plus::doBlockComment(comment_mode currCommentMode)
|
||||
return false;
|
||||
}
|
||||
|
||||
generic_string comment(commentLineSybol);
|
||||
comment += TEXT(" ");
|
||||
//For Single Line NORMAL MODE
|
||||
generic_string comment;
|
||||
size_t comment_length = 0;
|
||||
|
||||
//For Single Line ADVANCED MODE
|
||||
generic_string advCommentStart;
|
||||
generic_string advCommentEnd;
|
||||
size_t advCommentStart_length = 0;
|
||||
size_t advCommentEnd_length = 0;
|
||||
|
||||
const TCHAR aSpace[] { TEXT(" ") };
|
||||
|
||||
//Only values that have passed through will be assigned, to be sure they are valid!
|
||||
if (not isSingleLineAdvancedMode)
|
||||
{
|
||||
comment = commentLineSymbol;
|
||||
comment += aSpace;
|
||||
|
||||
comment_length = comment.length();
|
||||
}
|
||||
else // isSingleLineAdvancedMode
|
||||
{
|
||||
advCommentStart = commentStart;
|
||||
advCommentStart += aSpace;
|
||||
advCommentEnd = aSpace;
|
||||
advCommentEnd += commentEnd;
|
||||
|
||||
advCommentStart_length = advCommentStart.length();
|
||||
advCommentEnd_length = advCommentEnd.length();
|
||||
}
|
||||
|
||||
size_t comment_length = comment.length();
|
||||
size_t selectionStart = _pEditView->execute(SCI_GETSELECTIONSTART);
|
||||
size_t selectionEnd = _pEditView->execute(SCI_GETSELECTIONEND);
|
||||
size_t caretPosition = _pEditView->execute(SCI_GETCURRENTPOS);
|
||||
@ -3870,73 +3918,172 @@ bool Notepad_plus::doBlockComment(comment_mode currCommentMode)
|
||||
int selStartLine = static_cast<int32_t>(_pEditView->execute(SCI_LINEFROMPOSITION, selectionStart));
|
||||
int selEndLine = static_cast<int32_t>(_pEditView->execute(SCI_LINEFROMPOSITION, selectionEnd));
|
||||
int lines = selEndLine - selStartLine;
|
||||
size_t firstSelLineStart = _pEditView->execute(SCI_POSITIONFROMLINE, selStartLine);
|
||||
// "caret return" is part of the last selected line
|
||||
if ((lines > 0) && (selectionEnd == static_cast<size_t>(_pEditView->execute(SCI_POSITIONFROMLINE, selEndLine))))
|
||||
selEndLine--;
|
||||
//--FLS: count lines which were un-commented to decide if undoStreamComment() shall be called.
|
||||
int nUncomments = 0;
|
||||
//Some Lexers need line-comments at the beginning of a line.
|
||||
const bool avoidIndent = buf->getLangType() == L_FORTRAN_77;
|
||||
|
||||
_pEditView->execute(SCI_BEGINUNDOACTION);
|
||||
|
||||
for (int i = selStartLine; i <= selEndLine; ++i)
|
||||
{
|
||||
auto lineStart = _pEditView->execute(SCI_POSITIONFROMLINE, i);
|
||||
auto lineIndent = lineStart;
|
||||
auto lineEnd = _pEditView->execute(SCI_GETLINEENDPOSITION, i);
|
||||
size_t lineStart = _pEditView->execute(SCI_POSITIONFROMLINE, i);
|
||||
size_t lineIndent = _pEditView->execute(SCI_GETLINEINDENTPOSITION, i);
|
||||
size_t lineEnd = _pEditView->execute(SCI_GETLINEENDPOSITION, i);
|
||||
|
||||
size_t linebufferSize = lineEnd - lineStart + 2;
|
||||
// empty lines are not commented
|
||||
if (lineIndent == lineEnd)
|
||||
continue;
|
||||
|
||||
if (avoidIndent)
|
||||
lineIndent = lineStart;
|
||||
|
||||
size_t linebufferSize = lineEnd - lineIndent + 2;
|
||||
TCHAR* linebuf = new TCHAR[linebufferSize];
|
||||
|
||||
Lang *lang = _pEditView->getCurrentBuffer()->getCurrentLang();
|
||||
bool isFortran = lang == NULL?false:lang->_langID == L_FORTRAN_77;
|
||||
if (!isFortran)
|
||||
lineIndent = _pEditView->execute(SCI_GETLINEINDENTPOSITION, i);
|
||||
_pEditView->getGenericText(linebuf, linebufferSize, lineIndent, lineEnd);
|
||||
|
||||
generic_string linebufStr = linebuf;
|
||||
delete [] linebuf;
|
||||
|
||||
// empty lines are not commented
|
||||
if (linebufStr.length() < 1)
|
||||
continue;
|
||||
|
||||
if (currCommentMode != cm_comment)
|
||||
if (currCommentMode != cm_comment) // uncomment/toggle
|
||||
{
|
||||
if (not isSingleLineAdvancedMode)
|
||||
{
|
||||
//--FLS: In order to do get case insensitive comparison use strnicmp() instead case-sensitive comparison.
|
||||
// Case insensitive comparison is needed e.g. for "REM" and "rem" in Batchfiles.
|
||||
//if (linebufStr.substr(0, comment_length - 1) == comment.substr(0, comment_length - 1))
|
||||
if (generic_strnicmp(linebufStr.c_str(), comment.c_str(), comment_length -1) == 0)
|
||||
if (generic_strnicmp(linebufStr.c_str(), comment.c_str(), comment_length - 1) == 0)
|
||||
{
|
||||
generic_string commentStr = linebufStr.substr(0, comment_length);
|
||||
size_t len = (generic_strnicmp(commentStr.c_str(), comment.c_str(), comment_length) == 0) ? comment_length : comment_length - 1;
|
||||
size_t len = linebufStr[comment_length - 1] == aSpace[0] ? comment_length : comment_length - 1;
|
||||
|
||||
_pEditView->execute(SCI_SETSEL, lineIndent, lineIndent + len);
|
||||
_pEditView->replaceSelWith("");
|
||||
|
||||
if (i == selStartLine) // is this the first selected line?
|
||||
// SELECTION RANGE ADJUSTMENT .......................
|
||||
if (i == selStartLine) // first selected line
|
||||
{
|
||||
if (selectionStart > lineIndent + len)
|
||||
selectionStart -= len;
|
||||
selectionEnd -= len; // every iteration
|
||||
else if (selectionStart > lineIndent)
|
||||
selectionStart = lineIndent;
|
||||
} // ................................................
|
||||
if (i == selEndLine) // last selected line
|
||||
{
|
||||
if (selectionEnd > lineIndent + len)
|
||||
selectionEnd -= len;
|
||||
else if (selectionEnd > lineIndent)
|
||||
{
|
||||
selectionEnd = lineIndent;
|
||||
if (lineIndent == lineStart && i != selStartLine)
|
||||
++selectionEnd; // avoid caret return in this case
|
||||
}
|
||||
} // ................................................
|
||||
else // every iteration except the last selected line
|
||||
selectionEnd -= len;
|
||||
// ..................................................
|
||||
|
||||
++nUncomments;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ((currCommentMode == cm_toggle) || (currCommentMode == cm_comment))
|
||||
else // isSingleLineAdvancedMode
|
||||
{
|
||||
if ((generic_strnicmp(linebufStr.c_str(), advCommentStart.c_str(), advCommentStart_length - 1) == 0) &&
|
||||
(generic_strnicmp(linebufStr.substr(linebufStr.length() - advCommentEnd_length + 1, advCommentEnd_length - 1).c_str(), advCommentEnd.substr(1, advCommentEnd_length - 1).c_str(), advCommentEnd_length - 1) == 0))
|
||||
{
|
||||
size_t startLen = linebufStr[advCommentStart_length - 1] == aSpace[0] ? advCommentStart_length : advCommentStart_length - 1;
|
||||
size_t endLen = linebufStr[linebufStr.length() - advCommentEnd_length] == aSpace[0] ? advCommentEnd_length : advCommentEnd_length - 1;
|
||||
|
||||
_pEditView->execute(SCI_SETSEL, lineIndent, lineIndent + startLen);
|
||||
_pEditView->replaceSelWith("");
|
||||
_pEditView->execute(SCI_SETSEL, lineEnd - startLen - endLen, lineEnd - startLen);
|
||||
_pEditView->replaceSelWith("");
|
||||
|
||||
// SELECTION RANGE ADJUSTMENT .......................
|
||||
if (i == selStartLine) // first selected line
|
||||
{
|
||||
if (selectionStart > lineEnd - endLen)
|
||||
selectionStart = lineEnd - startLen - endLen;
|
||||
else if (selectionStart > lineIndent + startLen)
|
||||
selectionStart -= startLen;
|
||||
else if (selectionStart > lineIndent)
|
||||
selectionStart = lineIndent;
|
||||
} // ................................................
|
||||
if (i == selEndLine) // last selected line
|
||||
{
|
||||
if (selectionEnd > lineEnd)
|
||||
selectionEnd -= (startLen + endLen);
|
||||
else if (selectionEnd > lineEnd - endLen)
|
||||
selectionEnd = lineEnd - startLen - endLen;
|
||||
else if (selectionEnd > lineIndent + startLen)
|
||||
selectionEnd -= startLen;
|
||||
else if (selectionEnd > lineIndent)
|
||||
{
|
||||
selectionEnd = lineIndent;
|
||||
if (lineIndent == lineStart && i != selStartLine)
|
||||
++selectionEnd; // avoid caret return in this case
|
||||
}
|
||||
} // ................................................
|
||||
else // every iteration except the last selected line
|
||||
selectionEnd -= (startLen + endLen);
|
||||
// ..................................................
|
||||
|
||||
++nUncomments;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} // uncomment/toggle
|
||||
|
||||
if (currCommentMode != cm_uncomment) // comment/toggle
|
||||
{
|
||||
if (not isSingleLineAdvancedMode)
|
||||
{
|
||||
if (i == selStartLine) // is this the first selected line?
|
||||
selectionStart += comment_length;
|
||||
selectionEnd += comment_length; // every iteration
|
||||
_pEditView->insertGenericTextFrom(lineIndent, comment.c_str());
|
||||
}
|
||||
}
|
||||
// after uncommenting selection may promote itself to the lines
|
||||
// before the first initially selected line;
|
||||
// another problem - if only comment symbol was selected;
|
||||
if (selectionStart < firstSelLineStart)
|
||||
|
||||
// SELECTION RANGE ADJUSTMENT .......................
|
||||
if (i == selStartLine) // first selected line
|
||||
{
|
||||
if (selectionStart >= selectionEnd - (comment_length - 1))
|
||||
selectionEnd = firstSelLineStart;
|
||||
selectionStart = firstSelLineStart;
|
||||
if (selectionStart >= lineIndent)
|
||||
selectionStart += comment_length;
|
||||
} // ................................................
|
||||
if (i == selEndLine) // last selected line
|
||||
{
|
||||
if (selectionEnd >= lineIndent)
|
||||
selectionEnd += comment_length;
|
||||
} // ................................................
|
||||
else // every iteration except the last selected line
|
||||
selectionEnd += comment_length;
|
||||
// ..................................................
|
||||
}
|
||||
else // isSingleLineAdvancedMode
|
||||
{
|
||||
_pEditView->insertGenericTextFrom(lineIndent, advCommentStart.c_str());
|
||||
_pEditView->insertGenericTextFrom(lineEnd + advCommentStart_length, advCommentEnd.c_str());
|
||||
|
||||
// SELECTION RANGE ADJUSTMENT .......................
|
||||
if (i == selStartLine) // first selected line
|
||||
{
|
||||
if (selectionStart >= lineIndent)
|
||||
selectionStart += advCommentStart_length;
|
||||
} // ................................................
|
||||
if (i == selEndLine) // last selected line
|
||||
{
|
||||
if (selectionEnd > lineEnd)
|
||||
selectionEnd += (advCommentStart_length + advCommentEnd_length);
|
||||
else if (selectionEnd >= lineIndent)
|
||||
selectionEnd += advCommentStart_length;
|
||||
} // ................................................
|
||||
else // every iteration except the last selected line
|
||||
selectionEnd += (advCommentStart_length + advCommentEnd_length);
|
||||
// ..................................................
|
||||
}
|
||||
} // comment/toggle
|
||||
} // for (...)
|
||||
|
||||
if (move_caret)
|
||||
{
|
||||
// moving caret to the beginning of selected block
|
||||
|
Loading…
Reference in New Issue
Block a user