void SmartIndentPascal::DoUnIndent(cbEditor* ed, const wxString& WXUNUSED(langname)) const
{
    cbStyledTextCtrl* stc = ed->GetControl();

    wxString str = stc->GetLine(stc->GetCurrentLine()).Lower();
    str.Trim(false);
    str.Trim(true);

    int pos = stc->GetCurrentPos() - 4;
    if ( str.Matches( wxT("end")) )
        pos = FindBlockStart(stc, pos, wxT("begin"), wxT("end"), false );
    else
        pos = -1;
    if (pos != -1)
    {
        wxString indent = ed->GetLineIndentString(stc->LineFromPosition(pos));
        indent += str;
        stc->BeginUndoAction();
        stc->DelLineLeft();
        stc->DelLineRight();
        pos = stc->GetCurrentPos();
        stc->InsertText(pos, indent);
        stc->GotoPos(pos + indent.Length());
        stc->ChooseCaretX();
        stc->EndUndoAction();
    }
}
Example #2
0
void CodeEditor::OnCharAdded(wxScintillaEvent &event)
{
	char ch = event.GetKey();
	int currentLine = GetCurrentLine();
	int pos = GetCurrentPos();

	if (ch == wxT('\n') && currentLine > 0)
	{
		BeginUndoAction();

		wxString indent = GetLineIndentString(currentLine - 1);

		wxChar b = GetLastNonWhitespaceChar();
		if(b == wxT('{'))
		{
			if(GetUseTabs())
				indent << wxT("\t");
			else
				indent << wxT("    ");
		}

		InsertText(pos, indent);
		GotoPos((int)(pos + indent.Length()));
		ChooseCaretX();

		EndUndoAction();
	}
	else if(ch == wxT('}'))
	{
		BeginUndoAction();

		wxString line = GetLine(currentLine);
		line.Trim(false);
		line.Trim(true);
		if(line.Matches(wxT("}")))
		{
			pos = GetCurrentPos() - 2;
			pos = FindBlockStart(pos, wxT('{'), wxT('}'));

			if(pos != -1)
			{
				wxString indent = GetLineIndentString(LineFromPosition(pos));
				indent << wxT('}');
				DelLineLeft();
				DelLineRight();
				pos = GetCurrentPos();
				InsertText(pos, indent);
				GotoPos((int)(pos + indent.Length()));
				ChooseCaretX();
			}
		}

		EndUndoAction();
	}
}
void SmartIndentCpp::DoSmartIndent(cbEditor* ed, const wxChar &ch)const
{
    static bool autoIndentStart = false;
    static bool autoIndentDone = true;
    static int autoIndentLine = -1;
    static int autoIndentLineIndent = -1;

    static bool autoUnIndent = false; // for public: / case: / etc..
    static int autoUnIndentValue = -1;
    static int autoUnIndentLine = -1;

    cbStyledTextCtrl* stc = ed->GetControl();

    const int pos = stc->GetCurrentPos();
    // indent
    if ( (ch == _T('\n')) || ( (stc->GetEOLMode() == wxSCI_EOL_CR) && (ch == _T('\r')) ) )
    {
        stc->BeginUndoAction();
        // new-line: adjust indentation
        bool autoIndent = AutoIndentEnabled();
        bool smartIndent = SmartIndentEnabled();
        int currLine = stc->LineFromPosition(pos);
        if (autoIndent && currLine > 0)
        {
            wxString indent;
            if (stc->GetCurLine().Trim().IsEmpty())
            {
                // copy the indentation of the last non-empty line
                for (int i = currLine - 1; i >= 0; --i)
                {
                    const wxString& prevLineStr = stc->GetLine(i);
                    if (!(prevLineStr.IsEmpty() || prevLineStr[0] == _T('\n') || prevLineStr[0] == _T('\r')))
                    {
                        indent = ed->GetLineIndentString(i);
                        break;
                    }
                }
            }
            else
                indent = ed->GetLineIndentString(currLine - 1);
            if (smartIndent)
            {
                wxChar b = GetLastNonWhitespaceChar(ed);
                // if the last entered char before newline was an opening curly brace,
                // increase indentation level (the closing brace is handled in another block)

                if (!BraceIndent(stc, indent))
                {
                    if (b == _T('{'))
                    {
                        int nonblankpos;
                        wxChar c = GetNextNonWhitespaceCharOfLine(stc, pos, &nonblankpos);

                        if ( c != _T('}') )
                            Indent(stc, indent);
                        else
                        {
                            if ( pos != nonblankpos )
                            {
                                stc->SetCurrentPos(nonblankpos);
                                stc->DeleteBack();
                            }
                        }
                    }
                    else if (b == _T(':'))
                        Indent(stc, indent);
                }

            }
            stc->InsertText(pos, indent);
            stc->GotoPos(pos + indent.Length());
            stc->ChooseCaretX();
        }

        // smart indent
        if (smartIndent && currLine > 0)
        {
            if (!autoIndentDone)
            {
                bool valid = true;
                int line = stc->GetCurrentLine();
                if (line < autoIndentLine)
                    valid = false;
                else
                {
                    while (--line > autoIndentLine)
                    {
                        if (stc->GetLineIndentation(line) < autoIndentLineIndent)
                        {
                            valid = false;
                            break;
                        }
                    }
                }

                if (!valid)
                {
                    autoIndentStart = false;
                    autoIndentDone = true;
                    autoIndentLine = -1;
                    autoIndentLineIndent = -1;
                }
            }

            if (autoIndentDone)
            {
                const int ind_pos = stc->GetLineIndentPosition(currLine - 1);
                const wxString text = stc->GetTextRange(ind_pos, stc->WordEndPosition(ind_pos, true));
                if (   text == _T("if")
                    || text == _T("else")
                    || text == _T("for")
                    || text == _T("while")
                    || text == _T("do") )
                {
                    const wxChar non_ws_ch = GetLastNonWhitespaceChar(ed);
                    if (non_ws_ch != _T(';') && non_ws_ch != _T('}'))
                    {
                        autoIndentDone = false;
                        autoIndentLine = currLine - 1;
                        autoIndentLineIndent = stc->GetLineIndentation(currLine - 1);
                    }
                }
            }

            if (!autoIndentDone)
            {
                if (autoIndentStart)
                {
                    const wxChar non_ws_ch = GetLastNonWhitespaceChar(ed);
                    if (non_ws_ch == _T(';') || non_ws_ch == _T('}'))
                    {
                        stc->SetLineIndentation(currLine, autoIndentLineIndent);
                        stc->GotoPos(stc->GetLineEndPosition(currLine));

                        autoIndentStart = false;
                        autoIndentDone = true;
                        autoIndentLine = -1;
                        autoIndentLineIndent = -1;
                    }
                }
                else
                {
                    int lastLine = currLine;
                    while (--lastLine >= 0)
                    {
                        const int lineIndentPos = stc->GetLineIndentPosition(lastLine);
                        const int start = stc->WordStartPosition(lineIndentPos, true);
                        const int end = stc->WordEndPosition(lineIndentPos, true);
                        const wxString last = stc->GetTextRange(start, end);

                        if (   last == _T("if")
                            || last == _T("else")
                            || last == _T("for")
                            || last == _T("while")
                            || last == _T("do") )
                        {
                            const wxString text = stc->GetTextRange(lineIndentPos + last.Len(), pos);
                            int level = 0;
                            for (size_t i = 0; i < text.Len(); ++i)
                            {
                                if (text[i] == _T('('))
                                {
                                    const int style = stc->GetStyleAt(pos - text.Len() + i);
                                    if (   stc->IsString(style)
                                        || stc->IsCharacter(style)
                                        || stc->IsComment(style) )
                                    {
                                        continue;
                                    }
                                    ++level;
                                }
                                else if (text[i] == _T(')'))
                                {
                                    const int style = stc->GetStyleAt(pos - text.Len() + i);
                                    if (   stc->IsString(style)
                                        || stc->IsCharacter(style)
                                        || stc->IsComment(style) )
                                    {
                                        continue;
                                    }
                                    --level;
                                }
                            }

                            if (!level)
                            {
                                autoIndentStart = true;

                                int nonblankpos;
                                wxChar c = GetNextNonWhitespaceCharOfLine(stc, pos, &nonblankpos);
                                if (c == _T('}') && currLine == stc->LineFromPosition(nonblankpos))
                                {
                                    stc->NewLine();
                                    stc->GotoPos(pos);

                                    autoIndentStart = false;
                                    autoIndentDone = true;
                                    autoIndentLine = -1;
                                    autoIndentLineIndent = -1;
                                }

                                stc->Tab();
                            }

                            break;
                        }
                    }
                }
            }

            // smart un-indent
            if (autoUnIndent)
            {
                if ( GetLastNonWhitespaceChar(ed) == _T(':'))
                {
                    stc->SetLineIndentation(autoUnIndentLine, autoUnIndentValue);
                    stc->SetLineIndentation(currLine, autoUnIndentValue);
                    stc->Tab();
                }

                autoUnIndent = false;
                autoUnIndentValue = -1;
                autoUnIndentLine = -1;
            }
        }

        stc->EndUndoAction();
    }

    // unindent
    else if (ch == _T('{'))
    {
        if (autoIndentStart)
        {
            bool valid = true;
            const int start = stc->PositionFromLine(autoIndentLine);
            const wxString text = stc->GetTextRange(start, pos);
            if (text.Find(_T('{')) != int(text.Len() - 1))
                valid = false;
            else
            {
                int line = stc->GetCurrentLine();
                if (line < autoIndentLine)
                    valid = false;
                else
                {
                    while (--line > autoIndentLine)
                    {
                        if (stc->GetLineIndentation(line) < autoIndentLineIndent)
                        {
                            valid = false;
                            break;
                        }
                    }
                }
            }

            if (valid)
            {
                stc->BeginUndoAction();
                stc->SetLineIndentation(stc->GetCurrentLine(), autoIndentLineIndent);
                stc->EndUndoAction();
            }

            autoIndentStart = false;
            autoIndentDone = true;
            autoIndentLine = -1;
            autoIndentLineIndent = -1;
        }
    }

    // unindent
    else if (ch == _T('}'))
    {
        bool smartIndent = Manager::Get()->GetConfigManager(_T("editor"))->ReadBool(_T("/smart_indent"), true);
        if ( smartIndent && ( (stc->GetLexer() == wxSCI_LEX_CPP) || (stc->GetLexer() == wxSCI_LEX_D) ) )
        {
            stc->BeginUndoAction();
            // undo block indentation, if needed
            wxString str = stc->GetLine(stc->GetCurrentLine());
            str.Trim(false);
            str.Trim(true);
            if (str.Matches(_T("}")))
            {
                // just the brace here; unindent
                // find opening brace (skipping nested blocks)
                int cur_pos = stc->GetCurrentPos() - 2;
                cur_pos = FindBlockStart(stc, cur_pos, _T('{'), _T('}'));
                if (cur_pos != -1)
                {
                    wxString indent = ed->GetLineIndentString(stc->LineFromPosition(cur_pos));
                    indent << _T('}');
                    stc->DelLineLeft();
                    stc->DelLineRight();
                    cur_pos = stc->GetCurrentPos();
                    stc->InsertText(cur_pos, indent);
                    stc->GotoPos(cur_pos + indent.Length());
                    stc->ChooseCaretX();
                }
            }
            stc->EndUndoAction();
        }
    }

    // unindent
    else if (ch == _T(':'))
    {
        bool smartIndent = Manager::Get()->GetConfigManager(_T("editor"))->ReadBool(_T("/smart_indent"), true);
        if (smartIndent && stc->GetLexer() == wxSCI_LEX_CPP && !autoUnIndent)
        {
            const int curLine = stc->GetCurrentLine();
            const int li_pos = stc->GetLineIndentPosition(curLine);
            const wxString text = stc->GetTextRange(li_pos, stc->WordEndPosition(li_pos, true));
            if (   text == _T("public")
                || text == _T("protected")
                || text == _T("private")
                || text == _T("case")
                || text == _T("default") )
            {
                const bool isSwitch = (text == _T("case") || text == _T("default"));
                int lastLine = curLine;
                int lastLineIndent = -1;
                while (--lastLine >= 0)
                {
                    const int lineIndentPos = stc->GetLineIndentPosition(lastLine);
                    const int start = stc->WordStartPosition(lineIndentPos, true);
                    const int end = stc->WordEndPosition(lineIndentPos, true);

                    const wxString last = stc->GetTextRange(start, end);
                    if (last.IsEmpty())
                        continue;

                    if (isSwitch)
                    {
                        if (last == _T("case"))
                        {
                            lastLineIndent = stc->GetLineIndentation(lastLine);
                            break;
                        }
                        else if (last == _T("switch"))
                            break;
                    }
                    else
                    {
                        if (   last == _T("public")
                            || last == _T("protected")
                            || last == _T("private") )
                        {
                            lastLineIndent = stc->GetLineIndentation(lastLine);
                            break;
                        }
                        else if (last == _T("class"))
                            break;
                    }
                }

                if (lastLineIndent != -1)
                {
                    autoUnIndent = true;
                    autoUnIndentValue = lastLineIndent;
                    autoUnIndentLine = curLine;
                }
                else
                {
                    const int curLineIndent = stc->GetLineIndentation(curLine);
                    const int tabWidth = stc->GetTabWidth();
                    if (curLineIndent >= tabWidth)
                    {
                        autoUnIndent = true;
                        autoUnIndentValue = curLineIndent - tabWidth;
                        autoUnIndentLine = curLine;
                    }
                }
            }
        }
    }

}