tdf#140004 Toggle comment in the Basic IDE
This patch adds the "toggle comment" functionality to the Basic IDE. The shortcut Ctrl + Alt + C is used to execute it. It works similarly to other code editors such as Kate and VSCode. Change-Id: Ifdae42b3729cc909baf87c729fe8c3cdf6428184 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162005 Reviewed-by: Andreas Heinisch <andreas.heinisch@yahoo.de> Tested-by: Andreas Heinisch <andreas.heinisch@yahoo.de>
This commit is contained in:
parent
7bcce4180d
commit
22b5007e27
10 changed files with 228 additions and 1 deletions
|
@ -688,6 +688,12 @@ shell basctl_Shell
|
|||
ExecMethod = ExecuteDialog;
|
||||
StateMethod = GetState;
|
||||
]
|
||||
|
||||
SID_TOGGLE_COMMENT
|
||||
[
|
||||
StateMethod = GetState;
|
||||
ExecMethod = ExecuteGlobal;
|
||||
]
|
||||
}
|
||||
|
||||
interface BasicIDEDocument
|
||||
|
|
|
@ -1066,6 +1066,12 @@ void ModulWindow::ExecuteGlobal (SfxRequest& rReq)
|
|||
GetDispatcher()->Execute(SID_GOTOLINE);
|
||||
}
|
||||
break;
|
||||
|
||||
case SID_TOGGLE_COMMENT:
|
||||
{
|
||||
GetEditView()->ToggleComment();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1235,6 +1235,13 @@ void Shell::GetState(SfxItemSet &rSet)
|
|||
rSet.DisableItem( nWh );
|
||||
}
|
||||
break;
|
||||
case SID_TOGGLE_COMMENT:
|
||||
{
|
||||
// Only available in a ModulWindow if the document can be edited
|
||||
if (pCurWin && (!dynamic_cast<ModulWindow*>(pCurWin.get()) || pCurWin->IsReadOnly()))
|
||||
rSet.DisableItem(nWh);
|
||||
}
|
||||
break;
|
||||
case SID_GOTOLINE:
|
||||
{
|
||||
// if this is not a module window hide the
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
<menu:menuitem menu:id=".uno:Paste"/>
|
||||
<menu:menuseparator/>
|
||||
<menu:menuitem menu:id=".uno:SelectAll"/>
|
||||
<menu:menuitem menu:id=".uno:ToggleComment"/>
|
||||
<menu:menuseparator/>
|
||||
<menu:menuitem menu:id="vnd.sun.star.findbar:FocusToFindbar"/>
|
||||
<menu:menuitem menu:id=".uno:SearchDialog"/>
|
||||
|
@ -177,4 +178,3 @@
|
|||
</menu:menupopup>
|
||||
</menu:menu>
|
||||
</menu:menubar>
|
||||
|
||||
|
|
|
@ -670,6 +670,7 @@ class SvxZoomItem;
|
|||
#define SID_BASICIDE_WATCH TypedWhichId<SfxBoolItem>( SID_BASICIDE_START + 55 )
|
||||
#define SID_BASICIDE_STACK TypedWhichId<SfxBoolItem>( SID_BASICIDE_START + 56 )
|
||||
#define SID_BASICIDE_COLOR_SCHEME_DLG ( SID_BASICIDE_START + 57 )
|
||||
#define SID_TOGGLE_COMMENT ( SID_BASICIDE_START + 58 )
|
||||
#define SID_OPTIONS_TREEDIALOG ( SID_BASICIDE_START + 862)
|
||||
#define SID_OPTIONS_SECURITY ( SID_BASICIDE_START + 863)
|
||||
|
||||
|
|
|
@ -222,6 +222,9 @@ public:
|
|||
|
||||
bool IndentBlock();
|
||||
bool UnindentBlock();
|
||||
|
||||
// Used in the Basic IDE to toggle comment on a block of code
|
||||
void ToggleComment();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -371,6 +371,12 @@ Ctrl+Shift+e aka E_SHIFT_MOD1 under GTK/IBUS is for some emoji thing
|
|||
</node>
|
||||
<node oor:name="Modules">
|
||||
<node oor:name="com.sun.star.script.BasicIDE" oor:op="replace">
|
||||
<node oor:name="C_MOD1_MOD2" oor:op="replace">
|
||||
<prop oor:name="Command">
|
||||
<value xml:lang="x-no-translate">L10N SHORTCUTS - NO TRANSLATE</value>
|
||||
<value xml:lang="en-US">.uno:ToggleComment</value>
|
||||
</prop>
|
||||
</node>
|
||||
<node oor:name="F5" oor:op="replace">
|
||||
<prop oor:name="Command">
|
||||
<value xml:lang="x-no-translate">L10N SHORTCUTS - NO TRANSLATE</value>
|
||||
|
|
|
@ -18,6 +18,11 @@
|
|||
<value xml:lang="en-US">Line Numbers</value>
|
||||
</prop>
|
||||
</node>
|
||||
<node oor:name=".uno:ToggleComment" oor:op="replace">
|
||||
<prop oor:name="Label" oor:type="xs:string">
|
||||
<value xml:lang="en-US">Toggle Comment</value>
|
||||
</prop>
|
||||
</node>
|
||||
<node oor:name=".uno:InsertFormRadio" oor:op="replace">
|
||||
<prop oor:name="Label" oor:type="xs:string">
|
||||
<value xml:lang="en-US">Form Option Button</value>
|
||||
|
|
|
@ -2393,6 +2393,22 @@ SfxBoolItem ShowLines SID_SHOWLINES
|
|||
GroupId = SfxGroupId::Macro;
|
||||
]
|
||||
|
||||
SfxVoidItem ToggleComment SID_TOGGLE_COMMENT
|
||||
()
|
||||
[
|
||||
AutoUpdate = TRUE,
|
||||
FastCall = FALSE,
|
||||
ReadOnlyDoc = TRUE,
|
||||
Toggle = FALSE,
|
||||
Container = FALSE,
|
||||
RecordAbsolute = FALSE,
|
||||
RecordPerSet;
|
||||
|
||||
AccelConfig = TRUE,
|
||||
MenuConfig = TRUE,
|
||||
ToolBoxConfig = TRUE,
|
||||
GroupId = SfxGroupId::Macro;
|
||||
]
|
||||
|
||||
SfxVoidItem RunMacro SID_RUNMACRO
|
||||
()
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <memory>
|
||||
#include <i18nutil/searchopt.hxx>
|
||||
#include <o3tl/deleter.hxx>
|
||||
#include <o3tl/string_view.hxx>
|
||||
#include <utility>
|
||||
#include <vcl/textview.hxx>
|
||||
#include <vcl/texteng.hxx>
|
||||
|
@ -2234,5 +2235,181 @@ bool TextView::UnindentBlock()
|
|||
return ImpIndentBlock( false );
|
||||
}
|
||||
|
||||
void TextView::ToggleComment()
|
||||
{
|
||||
/* To determines whether to add or remove comment markers, the rule is:
|
||||
* - If any of the lines in the selection does not start with a comment character "'"
|
||||
* or "REM" then the selection is commented
|
||||
* - Otherwise, the selection is uncommented (i.e. if all of the lines start with a
|
||||
* comment marker "'" or "REM")
|
||||
* - Empty lines, or lines with only blank spaces or tabs are ignored
|
||||
*/
|
||||
|
||||
TextEngine* pEngine = GetTextEngine();
|
||||
TextSelection aSel = GetSelection();
|
||||
sal_uInt32 nStartPara = aSel.GetStart().GetPara();
|
||||
sal_uInt32 nEndPara = aSel.GetEnd().GetPara();
|
||||
|
||||
// True = Comment character will be added; False = Comment marker will be removed
|
||||
bool bAddCommentChar = false;
|
||||
|
||||
// Indicates whether any change has been made
|
||||
bool bChanged = false;
|
||||
|
||||
// Indicates whether the selection is downwards (normal) or upwards (reversed)
|
||||
bool bSelReversed = false;
|
||||
|
||||
if (nEndPara < nStartPara)
|
||||
{
|
||||
std::swap(nStartPara, nEndPara);
|
||||
bSelReversed = true;
|
||||
}
|
||||
|
||||
for (sal_uInt32 n = nStartPara; n <= nEndPara; n++)
|
||||
{
|
||||
OUString sText = pEngine->GetText(n).trim();
|
||||
|
||||
// Empty lines or lines with only blank spaces and tabs are ignored
|
||||
if (sText.isEmpty())
|
||||
continue;
|
||||
|
||||
if (!sText.startsWith("'") && !sText.startsWithIgnoreAsciiCase("REM"))
|
||||
{
|
||||
bAddCommentChar = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Notice that a REM comment is only actually a comment if:
|
||||
// a) There is no subsequent character or
|
||||
// b) The subsequent character is a blank space or a tab
|
||||
OUString sRest;
|
||||
if (sText.startsWithIgnoreAsciiCase("REM", &sRest))
|
||||
{
|
||||
if (sRest.getLength() > 0 && !sRest.startsWith(" ") && !sRest.startsWith("\t"))
|
||||
{
|
||||
bAddCommentChar = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bAddCommentChar)
|
||||
{
|
||||
// For each line, determine the first position where there is a character that is not
|
||||
// a blank space or a tab; the comment marker will be the smallest such position
|
||||
size_t nCommentPos = std::string::npos;
|
||||
|
||||
for (sal_uInt32 n = nStartPara; n <= nEndPara; n++)
|
||||
{
|
||||
OUString sText = pEngine->GetText(n);
|
||||
std::u16string_view sLine(sText);
|
||||
sal_uInt32 nCharPos = sLine.find_first_not_of(u" \t");
|
||||
|
||||
// Update the position where to place the comment marker
|
||||
if (nCharPos < nCommentPos)
|
||||
nCommentPos = nCharPos;
|
||||
|
||||
// If the comment position is zero, then there's no more need to keep searching
|
||||
if (nCommentPos == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
// Insert the comment marker in all lines (except empty lines)
|
||||
for (sal_uInt32 n = nStartPara; n <= nEndPara; n++)
|
||||
{
|
||||
OUString sText = pEngine->GetText(n);
|
||||
std::u16string_view sLine(sText);
|
||||
if (o3tl::trim(sLine).length() > 0)
|
||||
{
|
||||
pEngine->ImpInsertText(TextPaM(n, nCommentPos), "' ");
|
||||
bChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// For each line, find the first comment marker and remove it
|
||||
for (sal_uInt32 nPara = nStartPara; nPara <= nEndPara; nPara++)
|
||||
{
|
||||
OUString sText = pEngine->GetText(nPara);
|
||||
if (!sText.isEmpty())
|
||||
{
|
||||
// Determine the position of the comment marker and check whether it's
|
||||
// a single quote "'" or a "REM" comment
|
||||
sal_Int32 nQuotePos = sText.indexOf("'");
|
||||
sal_Int32 nRemPos = sText.toAsciiUpperCase().indexOf("REM");
|
||||
|
||||
// An empty line or a line with only blank spaces or tabs needs to be skipped
|
||||
if (nQuotePos == -1 && nRemPos == -1)
|
||||
continue;
|
||||
|
||||
// nRemPos only refers to a comment if the subsequent character is a blank space or tab
|
||||
const sal_Int32 nRemSub = nRemPos + 3;
|
||||
if (nRemPos != -1 && nRemPos < sText.getLength() - 3 &&
|
||||
sText.indexOf(" ", nRemSub) != nRemSub &&
|
||||
sText.indexOf("\t", nRemSub) != nRemSub)
|
||||
{
|
||||
nRemPos = -1;
|
||||
}
|
||||
|
||||
// True = comment uses single quote; False = comment uses REM
|
||||
bool bQuoteComment = true;
|
||||
|
||||
// Start and end positions to be removed
|
||||
sal_Int32 nStartPos = nQuotePos;
|
||||
sal_Int32 nEndPos = nStartPos + 1;
|
||||
|
||||
if (nQuotePos == -1)
|
||||
bQuoteComment = false;
|
||||
else if (nRemPos != -1 && nRemPos < nQuotePos)
|
||||
bQuoteComment = false;
|
||||
|
||||
if (!bQuoteComment)
|
||||
{
|
||||
nStartPos = nRemPos;
|
||||
nEndPos = nStartPos + 3;
|
||||
}
|
||||
|
||||
// Check if the next character is a blank space or a tab
|
||||
if (sText.indexOf(" ", nEndPos) == nEndPos || sText.indexOf("\t", nEndPos) == nEndPos)
|
||||
nEndPos++;
|
||||
|
||||
// Remove the comment marker
|
||||
pEngine->ImpDeleteText(TextSelection(TextPaM(nPara, nStartPos), TextPaM(nPara, nEndPos)));
|
||||
bChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update selection if there was a selection in the first place
|
||||
if (bChanged)
|
||||
{
|
||||
TextPaM aNewStart;
|
||||
if (!bSelReversed)
|
||||
aNewStart = TextPaM(nStartPara, std::min(aSel.GetStart().GetIndex(),
|
||||
pEngine->GetText(nStartPara).getLength()));
|
||||
else
|
||||
aNewStart = TextPaM(nStartPara, std::min(aSel.GetEnd().GetIndex(),
|
||||
pEngine->GetText(nEndPara).getLength()));
|
||||
|
||||
if (HasSelection())
|
||||
{
|
||||
TextPaM aNewEnd;
|
||||
if (!bSelReversed)
|
||||
aNewEnd = TextPaM(nEndPara, pEngine->GetText(nEndPara).getLength());
|
||||
else
|
||||
aNewEnd = TextPaM(nEndPara, pEngine->GetText(nStartPara).getLength());
|
||||
|
||||
TextSelection aNewSel(aNewStart, aNewEnd);
|
||||
ImpSetSelection(aNewSel);
|
||||
}
|
||||
else
|
||||
{
|
||||
TextSelection aNewSel(aNewStart, aNewStart);
|
||||
ImpSetSelection(aNewSel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||
|
|
Loading…
Reference in a new issue