Feature #25 Fast commenting

This commit is contained in:
Zane U. Ji 2014-04-18 23:11:13 +08:00
parent fe0102dddd
commit fe2cd0713b
5 changed files with 232 additions and 29 deletions

View File

@ -1,4 +1,5 @@
1.2.1.1 1.2.1.1
+ Feature #25 Fast commenting
+ x64 installation package + x64 installation package
* Fixed tab order * Fixed tab order
* Fixed encoding problems * Fixed encoding problems

View File

@ -131,6 +131,7 @@ BEGIN_EVENT_TABLE ( MyFrame, wxFrame )
EVT_MENU ( ID_FIND, MyFrame::OnFind ) EVT_MENU ( ID_FIND, MyFrame::OnFind )
EVT_MENU ( ID_FIND_AGAIN, MyFrame::OnFindAgain ) EVT_MENU ( ID_FIND_AGAIN, MyFrame::OnFindAgain )
EVT_MENU ( ID_GOTO, MyFrame::OnGoto ) EVT_MENU ( ID_GOTO, MyFrame::OnGoto )
EVT_MENU ( ID_TOGGLE_COMMENT, MyFrame::OnToggleComment )
EVT_MENU ( ID_FEEDBACK, MyFrame::OnFeedback ) EVT_MENU ( ID_FEEDBACK, MyFrame::OnFeedback )
EVT_MENU ( ID_PREVIOUS_DOCUMENT, MyFrame::OnPreviousDocument ) EVT_MENU ( ID_PREVIOUS_DOCUMENT, MyFrame::OnPreviousDocument )
EVT_MENU ( ID_NEXT_DOCUMENT, MyFrame::OnNextDocument ) EVT_MENU ( ID_NEXT_DOCUMENT, MyFrame::OnNextDocument )
@ -2799,6 +2800,16 @@ void MyFrame::OnGlobalReplace ( wxCommandEvent& event )
statusProgress ( msg ); statusProgress ( msg );
} }
void MyFrame::OnToggleComment ( wxCommandEvent& event )
{
XmlDoc *doc = getActiveDocument();
if ( doc == NULL )
return;
wxBusyCursor cursor;
doc->toggleComment();
}
void MyFrame::OnFrameClose ( wxCloseEvent& event ) void MyFrame::OnFrameClose ( wxCloseEvent& event )
{ {
wxCommandEvent e; wxCommandEvent e;
@ -4936,6 +4947,10 @@ wxMenuBar *MyFrame::getMenuBar()
new wxMenuItem ( NULL, ID_GOTO, _ ( "G&o To...\tCtrl+G" ), _ ( "Go To..." ) ); new wxMenuItem ( NULL, ID_GOTO, _ ( "G&o To...\tCtrl+G" ), _ ( "Go To..." ) );
gotoItem->SetBitmap ( wxNullBitmap ); gotoItem->SetBitmap ( wxNullBitmap );
wxMenuItem *commentItem =
new wxMenuItem ( NULL, ID_TOGGLE_COMMENT, _ ( "&Toggle Comment\tCtrl+/" ), _ ( "Toggle Comment" ) );
commentItem->SetBitmap ( wxNullBitmap );
editMenu->Append ( undoItem ); editMenu->Append ( undoItem );
editMenu->Append ( redoItem ); editMenu->Append ( redoItem );
editMenu->AppendSeparator(); editMenu->AppendSeparator();
@ -4948,8 +4963,9 @@ wxMenuBar *MyFrame::getMenuBar()
editMenu->Append ( findAgainItem ); editMenu->Append ( findAgainItem );
editMenu->Append ( replaceItem ); editMenu->Append ( replaceItem );
editMenu->Append ( globalReplaceItem ); editMenu->Append ( globalReplaceItem );
editMenu->AppendSeparator();
editMenu->Append ( gotoItem ); editMenu->Append ( gotoItem );
editMenu->AppendSeparator();
editMenu->Append ( commentItem );
#ifndef __WXMSW__ #ifndef __WXMSW__
wxMenuItem *preferencesItem = wxMenuItem *preferencesItem =

View File

@ -109,6 +109,7 @@ enum
ID_FIND, ID_FIND,
ID_FIND_AGAIN, ID_FIND_AGAIN,
ID_GOTO, ID_GOTO,
ID_TOGGLE_COMMENT,
ID_PRINT, ID_PRINT,
ID_WORD_COUNT, ID_WORD_COUNT,
ID_PRINT_PREVIEW, ID_PRINT_PREVIEW,
@ -235,6 +236,7 @@ class MyFrame : public wxFrame
void OnFindReplace ( wxCommandEvent& event ); void OnFindReplace ( wxCommandEvent& event );
void OnCommand ( wxCommandEvent& event ); void OnCommand ( wxCommandEvent& event );
void OnGlobalReplace ( wxCommandEvent& event ); void OnGlobalReplace ( wxCommandEvent& event );
void OnToggleComment ( wxCommandEvent& event );
void OnWordCount ( wxCommandEvent& event ); void OnWordCount ( wxCommandEvent& event );
void OnFeedback ( wxCommandEvent& event ); void OnFeedback ( wxCommandEvent& event );
void OnSplitTab ( wxCommandEvent& event ); void OnSplitTab ( wxCommandEvent& event );

View File

@ -973,40 +973,102 @@ wxString XmlCtrl::getLastAttributeName ( int pos )
return GetTextRange ( startPos + 1, pos ); return GetTextRange ( startPos + 1, pos );
} }
int XmlCtrl::getParentCloseAngleBracket ( int pos, int range ) int XmlCtrl::findNextEndTag (
int pos,
unsigned depth /*= 1*/,
int character /*= '>'*/,
int range /*= USHRT_MAX * 4*/ )
{ {
int cutoff, iteratorPos, depth; wxASSERT ( character == '<' || character == '>' );
cutoff = ( ( pos - range ) > 2 ) ? pos - range : 2;
depth = 1;
for (
iteratorPos = pos;
iteratorPos > cutoff;
--iteratorPos )
{
int type, style;
style = getLexerStyleAt ( iteratorPos );
if ( GetCharAt ( iteratorPos ) == '>' && unsigned openAngleBrackets = 0;
( style == wxSTC_H_TAG || int cutoff = pos + range;
style == wxSTC_H_TAGUNKNOWN ) ) if ( cutoff > GetEndStyled() )
cutoff = GetEndStyled();
for ( ; pos < cutoff; ++pos )
{ {
type = getTagType ( iteratorPos ); int ch = GetCharAt ( pos );
if ( ch == '<' )
openAngleBrackets = ( openAngleBrackets << 1 ) | 1;// Just a flag
// Check for empty tags, which have start tags but no end tags
if ( character != '>' || !openAngleBrackets )
if ( ch == '>' && getLexerStyleAt ( pos ) == wxSTC_H_TAGEND )
--depth;
if ( ch != character )
continue;
int style = getLexerStyleAt ( pos );
if ( style == wxSTC_H_TAG || style == wxSTC_H_TAGUNKNOWN )
{
int type = getTagType ( pos );
switch ( type ) switch ( type )
{ {
case ( TAG_TYPE_CLOSE ) : case TAG_TYPE_CLOSE:
++depth;
break;
case ( TAG_TYPE_OPEN ) :
--depth; --depth;
break; break;
case ( TAG_TYPE_EMPTY ) : case TAG_TYPE_OPEN:
case ( TAG_TYPE_OTHER ) : // In case that the cursor is inside a start tag
case ( TAG_TYPE_ERROR ) : if ( character != '>' || openAngleBrackets > 0 )
++depth;
break;
case TAG_TYPE_EMPTY:
case TAG_TYPE_OTHER:
case TAG_TYPE_ERROR:
break; break;
} }
if ( !depth )
return iteratorPos;
} }
if ( !depth )
return pos + 1;
}
return -1;
}
int XmlCtrl::findPreviousStartTag (
int pos,
unsigned depth /*= 1*/,
int character /*= '<'*/,
int range /*= USHRT_MAX * 4*/ )
{
wxASSERT ( character == '<' || character == '>' );
int cutoff = ( ( pos - range ) > 2 ) ? pos - range : 2;
unsigned closeAngleBrackets = 0;
while ( pos-- > cutoff )
{
int ch = GetCharAt ( pos );
if ( ch == '>' )
{
closeAngleBrackets = ( closeAngleBrackets << 1 ) | 1;// Just a flag
// Check for empty tags, which have start tags but no end tags
if ( character != '>' && getLexerStyleAt ( pos ) == wxSTC_H_TAGEND )
++depth;
}
if ( ch != character )
continue;
int style = getLexerStyleAt ( pos );
if ( style == wxSTC_H_TAG || style == wxSTC_H_TAGUNKNOWN )
{
int type = getTagType ( pos );
switch ( type )
{
case TAG_TYPE_CLOSE:
// If the cursor is already in an end tag
if ( character != '<' || closeAngleBrackets > 0 )
++depth;
break;
case TAG_TYPE_OPEN:
--depth;
break;
case TAG_TYPE_EMPTY:
case TAG_TYPE_OTHER:
case TAG_TYPE_ERROR:
break;
}
}
if ( !depth )
return pos;
} }
return -1; return -1;
} }
@ -2119,3 +2181,111 @@ void XmlCtrl::OnMiddleDown ( wxMouseEvent& event )
SetSelection ( pastePosition, pastePosition ); SetSelection ( pastePosition, pastePosition );
Paste(); Paste();
} }
void XmlCtrl::toggleComment()
{
int pos = -1;
wxString text = GetSelectedText();
if ( text.IsEmpty() )
{
if ( type == FILE_TYPE_BINARY )
return;
pos = GetCurrentPos();
Colourise ( 0, -1 );
int style = getLexerStyleAt ( pos ) ;
if ( style == wxSTC_H_COMMENT )
{
int i = pos;
while ( --i >= 0 && getLexerStyleAt ( i ) == wxSTC_H_COMMENT )
continue;
SetSelectionStart ( i + 1 );
int styled = GetEndStyled();
i = pos;
while ( i < styled && getLexerStyleAt ( i ) == wxSTC_H_COMMENT )
i++;
SetSelectionEnd ( i );
}
else
{
// Select current tag
int start = findPreviousStartTag ( pos, 1, '<', pos );
if ( start < 0 )
{
wxMessageBox(_T("Cann't find the start tag"));
return;
}
int range = GetTextLength() - pos;
int end = findNextEndTag ( pos, 1, '>', range );
if ( end < 0 )
{
wxMessageBox(_T("Cann't find the end tag"));
return;
}
SetSelection ( start, end );
}
text = GetSelectedText();
}
// Skip leading spaces
wxString::iterator itr, start, end;
itr = start = text.begin();
end = text.end();
while ( itr != end && wxIsspace ( *itr ) )
++itr;
const static wxString commentStart = _T ( "<!--" );
const static wxString commentEnd = _T ( "-->" );
size_t offset = itr - start;
int ret = text.compare ( offset, commentStart.length(), commentStart );
if ( ret == 0 )
{
start = itr;
itr = end;
do {
--itr;
} while ( itr != start && wxIsspace ( *itr ) );
offset = itr - start;
if ( offset > commentEnd.length() )
{
offset = itr - text.begin() - commentEnd.length() + 1;
ret = text.compare ( offset, commentEnd.length(), commentEnd );
// Is commented?
if ( ret == 0 )
{
text.erase ( offset, commentEnd.length() );
text.erase ( start, start + commentStart.length() );
ReplaceSelection ( text );
if ( pos >= 0 )
{
pos -= commentStart.length();
SetEmptySelection ( pos >= 0 ? pos : 0 );
}
return;
}
}
}
// Comment selection
// "--" is not allowed in comments
const static wxString doubleHyphen = _T ( "--" );
offset = 0;
while ( ( offset = text.find ( doubleHyphen, offset ) ) != wxString::npos )
{
text.replace ( offset, doubleHyphen.length(), _T ( "- -" ) );
offset += 2; // WARNING: Not three!
}
text = commentStart + text + commentEnd;
ReplaceSelection ( text );
if ( pos >= 0 )
SetEmptySelection ( pos + commentStart.length() );
}

View File

@ -109,7 +109,20 @@ class XmlCtrl: public wxStyledTextCtrl
long style = 0 ); long style = 0 );
~XmlCtrl(); ~XmlCtrl();
int getType(); int getType();
int getParentCloseAngleBracket ( int pos, int range = USHRT_MAX * 4 ); int getParentCloseAngleBracket ( int pos )
{
return findPreviousStartTag ( pos, 1, '>' );
}
int findNextEndTag (
int pos,
unsigned depth = 1,
int character = '>',
int range = USHRT_MAX * 4 );
int findPreviousStartTag (
int pos,
unsigned depth = 1,
int character = '<',
int range = USHRT_MAX * 4 );
void applyProperties ( void applyProperties (
const XmlCtrlProperties &propertiesParameter, const XmlCtrlProperties &propertiesParameter,
bool zoomOnly = false ); bool zoomOnly = false );
@ -144,6 +157,7 @@ class XmlCtrl: public wxStyledTextCtrl
std::string myGetTextRaw(); // alternative to faulty stc implementation std::string myGetTextRaw(); // alternative to faulty stc implementation
bool getValidationRequired(); bool getValidationRequired();
void setValidationRequired ( bool b ); void setValidationRequired ( bool b );
void toggleComment();
private: private:
ValidationThread *validationThread; // used for background validation ValidationThread *validationThread; // used for background validation