1
#include "SmartIndentXML.h"
3
#include <sdk.h> // Code::Blocks SDK
7
#include <configmanager.h>
8
#include <editormanager.h>
9
#include <editorcolourset.h>
15
#include <cbstyledtextctrl.h>
17
// Register the plugin with Code::Blocks.
18
// We are using an anonymous namespace so we don't litter the global one.
21
PluginRegistrant<SmartIndentXML> reg(wxT("SmartIndentXML"));
24
void SmartIndentXML::OnEditorHook(cbEditor* ed, wxScintillaEvent& event) const
26
// check if smart indent is enabled
27
// check the event type and the currently set language
28
// if it is not a CharAdded event or the language is neither XML nor HTML return
33
if ( !SmartIndentEnabled() )
36
wxEventType type = event.GetEventType();
37
if ( type != wxEVT_SCI_CHARADDED )
40
cbStyledTextCtrl* stc = ed->GetControl();
44
const int lexer = stc->GetLexer();
45
if (lexer != wxSCI_LEX_XML && lexer != wxSCI_LEX_HTML)
48
ed->AutoIndentDone(); // we are responsible
50
int pos = stc->GetCurrentPos();
51
int currLine = stc->LineFromPosition(pos);
53
const wxChar ch = event.GetKey();
54
wxRegEx reTag(wxT("***:<[ \t]*?(|/)[ \t]*?([a-zA-Z][a-zA-Z0-9_-]*).*?(|/)[ \t]*?>"));
56
bool complQuote = true;
57
if ( SelectionBraceCompletionEnabled() || stc->IsBraceShortcutActive() )
59
if (stc->DoSelectionBraceCompletion(ch))
62
pos = stc->GetCurrentPos();
63
currLine = stc->LineFromPosition(pos);
67
if (BraceCompletionEnabled())
69
int curSty = stc->GetStyleAt(pos);
70
// finish XML/HTML tag
71
if ( ch == wxT('>') && !stc->IsString(curSty) )
74
for (int i = pos - 2; i > 0; --i)
76
if (stc->GetCharAt(i) == wxT('<') || stc->GetCharAt(i) == wxT('>'))
78
tag = stc->GetTextRange(i, pos);
83
if (reTag.Matches(tag) && reTag.GetMatch(tag, 1).IsEmpty() && reTag.GetMatch(tag, 3).IsEmpty())
84
stc->InsertText(pos, wxT("</") + reTag.GetMatch(tag, 2) + wxT(">"));
87
else if (complQuote && (ch == wxT('"') || ch == wxT('\'')))
89
if (stc->GetCharAt(pos) == ch)
94
else if (!stc->IsString(stc->GetStyleAt(pos - 2)))
95
stc->InsertText(pos, ch);
97
else if (ch == wxT('?') && stc->GetCharAt(pos - 2) == wxT('<'))
100
for (int i = pos; i < stc->GetLength(); ++i)
102
if (stc->GetCharAt(i) == wxT('<') || stc->GetCharAt(i) == wxT('>'))
104
tag = stc->GetTextRange(i - 1, i + 1);
108
if (tag != wxT("?>"))
109
stc->InsertText(pos, wxT(" ?>"));
112
else if (ch == wxT('[') && pos > 8 && stc->GetTextRange(pos - 9, pos - 1) == wxT("<![CDATA"))
115
for (int i = pos; i < stc->GetLength(); ++i)
117
if (stc->GetCharAt(i) == wxT('<') || stc->GetCharAt(i) == wxT('>'))
119
tag = stc->GetTextRange(i - 2, i + 1);
123
if (tag != wxT("]]>"))
124
stc->InsertText(pos, wxT("]]>"));
126
// embedded languages
127
else if (complQuote && curSty >= wxSCI_HJ_START && curSty <= wxSCI_HPHP_OPERATOR && !stc->IsString(curSty))
129
stc->DoBraceCompletion(ch);
133
if ( AutoIndentEnabled()
134
&& ( (ch == wxT('\n')) || ((stc->GetEOLMode() == wxSCI_EOL_CR) && (ch == wxT('\r'))) ) )
136
wxString indent = ed->GetLineIndentString(currLine - 1);
137
stc->BeginUndoAction();
138
if (SmartIndentEnabled()) // smart indent
140
int idx = stc->GetLine(currLine - 1).Find(wxT('>'), true);
141
if (idx != wxNOT_FOUND)
144
for (int i = stc->PositionFromLine(currLine - 1) + idx - 1; i > 0; --i)
146
if (stc->GetCharAt(i) == wxT('<'))
148
tag = stc->GetTextRange(i, pos);
153
if (reTag.Matches(tag))
155
indent = ed->GetLineIndentString(stc->LineFromPosition(pos - tag.Length()));
157
if (reTag.GetMatch(tag, 1).IsEmpty() && reTag.GetMatch(tag, 3).IsEmpty())
159
wxString tagId = reTag.GetMatch(tag, 2);
160
// is close-tag after cursor?
161
tag = stc->GetLine(currLine);
162
if (reTag.Matches(tag) && !reTag.GetMatch(tag, 1).IsEmpty() && reTag.GetMatch(tag, 2) == tagId)
164
if (wxIsspace(stc->GetCharAt(pos)))
166
stc->InsertText(pos, indent);
173
else if (stc->GetStyleAt(pos) >= wxSCI_HJ_START && stc->GetStyleAt(pos) <= wxSCI_HPHP_OPERATOR)
175
// embedded language, indent braces
176
const wxString lineSuffix = stc->GetLine(currLine).Strip(wxString::both);
177
if (lineSuffix == wxT('}') || lineSuffix == wxT(']'))
179
stc->InsertText(pos, GetEOLStr(stc->GetEOLMode()) + indent);
182
else if (GetLastNonWhitespaceChar(ed) == wxT('{'))
188
for (int i = stc->PositionFromLine(currLine - 1); i < stc->GetLineEndPosition(currLine - 1); ++i)
190
if (stc->GetStyleAt(i) == wxSCI_H_ATTRIBUTE || stc->GetStyleAt(i) == wxSCI_H_ATTRIBUTEUNKNOWN)
192
Indent(stc, indent, i - stc->PositionFromLine(currLine - 1));
193
if (stc->GetLineEndPosition(currLine) > pos + 2 && wxIsspace(stc->GetCharAt(pos)))
200
stc->InsertText(pos, indent);
201
stc->GotoPos(pos + indent.Length());
203
stc->EndUndoAction();