Index: CodeEditor.h
===================================================================
--- CodeEditor.h	(wersja 9430)
+++ CodeEditor.h	(kopia robocza)
@@ -141,6 +141,39 @@
 	virtual ~EditorBar();
 };
 
+// TODO: When C++11 will be avaliable in CodeEditor class replace with enum class
+// Current version is not typed safe!!!
+enum IdentType {
+	IDENT_TYPE_SPACE = 0,
+	IDENT_TYPE_TAB,
+	IDENT_TYPE_UNKNOWN
+};
+
+class IdentRecognizer {
+public:
+	IdentRecognizer(CodeEditor *editor, int spaceIdentDefaultSize = 4);
+	virtual ~IdentRecognizer();
+	
+	IdentType FindIdentType();
+	IdentType FindIdentType(const WString& line);
+	int       FindIdentLevel(const WString& line, IdentType type);
+	
+	int    GetSpaceIdentDefaultSize() const;
+	char   GetIdentChar(IdentType type);
+	String GetIdentString(IdentType type, int identLevel = 1);
+	int    GetIdentCharCount(IdentType type, int identLevel = 1);
+	
+	void SetSpaceIdentDefaultSize(int spaceIdentDefaultSize);
+	
+private:
+	IdentType FindIdentTypeInLine(const WString& line);
+	int       FindSpaceIdentSize();
+	
+private:
+	CodeEditor* editor;
+	int         spaceIdentDefaultSize;
+};
+
 struct IdentPos {
 	int    begin;
 	int    end;
Index: CodeEditor.upp
===================================================================
--- CodeEditor.upp	(wersja 9430)
+++ CodeEditor.upp	(kopia robocza)
@@ -29,8 +29,8 @@
 	TagSyntax.h,
 	TagSyntax.cpp,
 	PythonSyntax readonly separator,
+	PythonSyntax.h,
 	PythonSyntax.cpp,
-	PythonSyntax.h,
 	LogSyntax readonly separator,
 	LogSyntax.h,
 	LogSyntax.cpp,
@@ -38,6 +38,7 @@
 	EditorBar.cpp,
 	FindReplace.cpp,
 	Lang.cpp,
+	IndentRecognizer.cpp,
 	CodeEditor.cpp,
 	CodeEditor.lay,
 	CodeEditor.iml,
Index: IndentRecognizer.cpp
===================================================================
--- IndentRecognizer.cpp	(wersja 0)
+++ IndentRecognizer.cpp	(kopia robocza)
@@ -0,0 +1,129 @@
+#include "CodeEditor.h"
+
+NAMESPACE_UPP
+
+IdentRecognizer::IdentRecognizer(CodeEditor *editor, int spaceIdentDefaultSize)
+{
+	this->editor = editor;
+	this->spaceIdentDefaultSize = spaceIdentDefaultSize;
+}
+
+IdentRecognizer::~IdentRecognizer() {}
+
+int IdentRecognizer::FindIdentLevel(const WString& line, IdentType type)
+{
+	int level = 0;
+	for(int i = 0; i < line.GetLength(); i++) {
+		if(type == IDENT_TYPE_TAB && line[i] == '\t')
+			level++;
+		else
+		if(type == IDENT_TYPE_SPACE && line[i] == ' ')
+			level++;
+		else
+			break;
+	}
+	
+	if (type == IDENT_TYPE_SPACE)
+		level /= FindSpaceIdentSize();
+	
+	return level;
+}
+
+IdentType IdentRecognizer::FindIdentType(const WString& line)
+{
+	IdentType type = FindIdentTypeInLine(line);
+	if(type == IDENT_TYPE_UNKNOWN)
+		type = FindIdentType();
+	return type;
+}
+
+IdentType IdentRecognizer::FindIdentType()
+{
+	IdentType type = IDENT_TYPE_UNKNOWN;
+	for(int i = 0; i < editor->GetLineCount(); i++) {
+		IdentType ctype = FindIdentTypeInLine(editor->GetWLine(i));
+		if(ctype != IDENT_TYPE_UNKNOWN) {
+			type = ctype;
+			break;
+		}
+	}
+	return type;
+}
+
+int IdentRecognizer::GetSpaceIdentDefaultSize() const
+{
+	return spaceIdentDefaultSize;
+}
+
+char IdentRecognizer::GetIdentChar(IdentType type)
+{
+	if(type == IDENT_TYPE_SPACE)
+		return ' ';
+	return '\t';
+}
+
+String IdentRecognizer::GetIdentString(IdentType type, int identLevel)
+{
+	String ident, baseIdent;
+	if(type == IDENT_TYPE_SPACE) {
+		for(int i = 0; i < FindSpaceIdentSize(); i++)
+			baseIdent += " ";
+	}
+	else
+		baseIdent = "\t";
+	
+	for(int i = 0 ; i < identLevel; i++)
+		ident += baseIdent;
+	
+	return ident;
+}
+
+int IdentRecognizer::GetIdentCharCount(IdentType type, int identLevel)
+{
+	return GetIdentString(type, identLevel).GetCount();
+}
+
+void IdentRecognizer::SetSpaceIdentDefaultSize(int spaceIdentDefaultSize)
+{
+	this->spaceIdentDefaultSize = spaceIdentDefaultSize;
+}
+
+IdentType IdentRecognizer::FindIdentTypeInLine(const WString& line)
+{
+	IdentType type = IDENT_TYPE_UNKNOWN;
+	if(line.StartsWith("\t"))
+		type = IDENT_TYPE_TAB;
+	else
+	if(line.StartsWith(" "))
+		type = IDENT_TYPE_SPACE;
+	return type;
+}
+
+int IdentRecognizer::FindSpaceIdentSize()
+{
+	int current = 0;
+	for(int i = 0; i < editor->GetLineCount(); i++) {
+		WString line = editor->GetWLine(i);
+		bool hasNonSpaceEnd = false;
+		for(int j = 0; j < line.GetLength(); j++) {
+			if(line[j] == ' ')
+				current++;
+			else {
+				hasNonSpaceEnd = true;
+				break;
+			}
+		}
+		
+		if(!hasNonSpaceEnd) {
+			current = 0;
+			continue;
+		}
+		else
+		if(current > 0)
+			break;
+	}
+	
+	return current > 0 ? current : spaceIdentDefaultSize;
+}
+
+END_UPP_NAMESPACE
Index: PythonSyntax.cpp
===================================================================
--- PythonSyntax.cpp	(wersja 9430)
+++ PythonSyntax.cpp	(kopia robocza)
@@ -68,19 +68,18 @@
 
 void PythonSyntax::IndentInsert(CodeEditor& editor, int chr, int count)
 {
+	IdentRecognizer recognizer(&editor);
+	
 	if(chr == '\n') {
 		while(count--) {
-			WString cursorLine = editor.GetWLine(editor.GetCursorLine());
+			WString line = editor.GetWLine(editor.GetCursorLine());
 			editor.InsertChar('\n', 1);
 			
-			Identation::Type idType = FindIdentationType(editor, cursorLine);
-			char idChar = GetIdentationByType(idType);
-			int mult = 1;
-			if(idType == Identation::Space)
-				mult = CalculateSpaceIndetationSize(editor);
-			if(LineHasColon(cursorLine))
-				editor.InsertChar(idChar, mult);
-			editor.InsertChar(idChar, CalculateLineIndetations(cursorLine, idType));
+			IdentType identType = recognizer.FindIdentType(line);
+			int level = recognizer.FindIdentLevel(line, identType);
+			if(LineHasColon(line))
+				level++;
+			editor.InsertChar(recognizer.GetIdentChar(identType), recognizer.GetIdentCharCount(identType, level));
 		}
 	}
 	if(count > 0)
@@ -142,6 +141,7 @@
 
 bool PythonSyntax::LineHasColon(const WString& line)
 {
+	// TODO: Bugfix is needed - what about cursor is not at the end of line???
 	for(int i = line.GetLength() - 1; i >= 0; i--) {
 		if(line[i] == ':')
 			return true;
@@ -149,71 +149,4 @@
 	return false;
 }
 
-int PythonSyntax::CalculateLineIndetations(const WString& line, Identation::Type type)
-{
-	int count = 0;
-	for(int i = 0; i < line.GetLength(); i++) {
-		if(type == Identation::Tab && line[i] == '\t')
-			count++;
-		else
-		if(type == Identation::Space && line[i] == ' ')
-			count++;
-		else
-			break;
-	}
-	return count;
-}
-
-PythonSyntax::Identation::Type PythonSyntax::FindIdentationType(CodeEditor& editor, const WString& line)
-{
-	Identation::Type type = Identation::None;
-	if(line.StartsWith("\t"))
-		type = Identation::Tab;
-	else
-	if(line.StartsWith(" "))
-		type = Identation::Space;
-	else {
-		for(int i = 0; i < editor.GetLineCount(); i++) {
-			WString cLine = editor.GetWLine(i);
-			if(cLine.StartsWith("\t")) {
-				type = Identation::Tab;
-				break;
-			}
-			else
-			if(cLine.StartsWith(" ")) {
-				type = Identation::Space;
-				break;
-			}
-		}
-	}
-	return type;
-}
-
-int PythonSyntax::CalculateSpaceIndetationSize(CodeEditor& editor)
-{
-	int current = 0;
-	for(int i = 0; i < editor.GetLineCount(); i++) {
-		WString line = editor.GetWLine(i);
-		for(int j = 0; j < line.GetLength(); j++) {
-			if(line[j] == ' ')
-				current++;
-			else
-				break;
-		}
-		
-		if(current > 0)
-			break;
-	}
-	
-	// TODO: 4 is magic numer - try to find the way to get this number from ide constants
-	return current > 0 ? current : 4;
-}
-
-char PythonSyntax::GetIdentationByType(Identation::Type type)
-{
-	if(type == Identation::Space)
-		return ' ';
-	return '\t';
-}
-
 END_UPP_NAMESPACE
Index: PythonSyntax.h
===================================================================
--- PythonSyntax.h	(wersja 9430)
+++ PythonSyntax.h	(kopia robocza)
@@ -1,13 +1,4 @@
 class PythonSyntax : public EditorSyntax {
-private:
-	struct Identation {
-		enum Type {
-			Tab = 0,
-			Space,
-			None
-		};
-	};
-
 public:
 	PythonSyntax();
 
@@ -26,10 +17,6 @@
 	void LoadSyntax(const char* keywordsArray[], const char* specialVarsArray[]);
 	
 	bool             LineHasColon(const WString& line);
-	int              CalculateLineIndetations(const WString& line, Identation::Type type);
-	int              CalculateSpaceIndetationSize(CodeEditor& editor);
-	Identation::Type FindIdentationType(CodeEditor& editor, const WString& line);
-	char             GetIdentationByType(Identation::Type type);
 	
 private:
 	Index<String> keywords;
Index: TagSyntax.cpp
===================================================================
--- TagSyntax.cpp	(wersja 9430)
+++ TagSyntax.cpp	(kopia robocza)
@@ -8,6 +8,8 @@
 	hout = NULL;
 	html = true;
 	witz = false;
+	
+	InitSpecialTags();
 }
 
 void TagSyntax::Clear()
@@ -278,9 +280,41 @@
 
 void TagSyntax::IndentInsert(CodeEditor& editor, int chr, int count)
 {
-	if(status == SCRIPT)
+	if(status == SCRIPT) {
 		script.IndentInsert(editor, chr, count);
+		return;
+	}
+	
+	IdentRecognizer recognizer(&editor);
+	if(chr == '\n') {
+		while(count--) {
+			WString line = editor.GetWLine(editor.GetCursorLine());
+			IdentType identType = recognizer.FindIdentType(line);
+			
+			int currentLevel = recognizer.FindIdentLevel(line, identType);
+			int newLevel = GetNewIdnetations(editor);
+			int level = currentLevel + newLevel;
+			
+			String afterCursor;
+			if(newLevel > 0) {
+				WString rightSide = GetCursorLineRightSide(editor);
+				if(rightSide.StartsWith("<")) {
+					afterCursor = "\n";
+					for(int i = 0; i < level - 1; i++)
+						afterCursor += recognizer.GetIdentString(identType);
+				}
+				else
+				if(!rightSide.IsEmpty())
+					level = 0;
+			}
+			
+			editor.InsertChar('\n', 1);
+			editor.InsertChar(recognizer.GetIdentChar(identType), recognizer.GetIdentCharCount(identType, level));
+			editor.Insert(editor.GetCursor(), afterCursor);
+		}
+	}
 	else
+	if(count > 0)
 		editor.InsertChar(chr, count);
 }
 
@@ -291,6 +325,164 @@
 	return false;
 }
 
+bool TagSyntax::HasHtmlTags() const
+{
+	return html || witz;
+}
+
+int TagSyntax::GetIdentationsLevel(CodeEditor& editor) const
+{
+	int level = 0;
+	WString line = editor.GetWLine(editor.GetCursorLine());
+	for(int i = 0; i < line.GetCount(); i++) {
+		if(line[i] == '\t')
+			level++;
+		else
+			break;
+	}
+	return level;
+}
+
+int TagSyntax::GetNewIdnetations(CodeEditor& editor) const
+{
+	int level = 0;
+	
+	WString leftSide = GetCursorLineLeftSide(editor);
+	WString rightSide = GetCursorLineRightSide(editor);
+	Vector< Tuple2<String, int> > types = SplitTagsByType(leftSide);
+	for(int i = 0; i < types.GetCount(); i++) {
+		if(types[i].b == TAG)
+			level++;
+		else
+		if(types[i].b == ENDTAG) {
+			if(level > 0)
+				level--;
+		}
+	}
+	if(IsCursorInsideTag(leftSide, rightSide))
+		level++;
+	
+	if(level < 0)
+		level++;
+	
+	return level;
+}
+
+Vector< Tuple2<String, int> > TagSyntax::SplitTagsByType(const WString& s) const
+{
+	Vector< Tuple2<String, int> > tags;
+	
+	wchar  strc;
+	bool   isStr = false;
+	bool   isTag = false;
+	int    type = TAG;
+	String name;
+	for(int i = 0; i < s.GetCount(); i++) {
+		wchar c = s[i];
+		
+		if(c == '\'' || c == '\"') {
+			if(!isStr) {
+				isStr = true;
+				strc = c;
+			}
+			else
+			if(isStr && c == strc)
+				isStr = false;
+		}
+		else
+		if(c == '<') {
+			isTag = true;
+			if(i + 1 >= s.GetCount())
+				continue;
+			wchar nc = s[i + 1];
+			if(nc == '/') {
+				type = ENDTAG;
+				i++;
+			}
+			else
+			if(nc == '!' || nc == '?') {
+				type = TAG0;
+				i++;
+			}
+			i++;
+			name = FindTagName(s, i);
+		}
+		else
+		if(c == '>') {
+			if(!isTag || i - 1 < 0)
+				continue;
+			
+			wchar pc = s[i - 1];
+			if(pc == '/' && type == TAG)
+				type = TAG0;
+			
+			if(HasHtmlTags() && type != TAG0) {
+				if(htmlSpecialTags.Find(name) > -1)
+					type = TAG0;
+			}
+			
+			tags.Add(Tuple<String, int>(name, type));
+			type = TAG;
+			isTag = false;
+		}
+	}
+	
+	return tags;
+}
+
+String TagSyntax::FindTagName(const WString& str, int& i) const
+{
+	String name;
+	while(i < str.GetCount()) {
+		if(str[i] == ' ' || str[i] == '>' || str[i] == '/') {
+			i--;
+			break;
+		}
+		name += str[i];
+		i++;
+	}
+	return name;
+}
+
+WString TagSyntax::GetCursorLineLeftSide(CodeEditor& editor) const
+{
+	int cursor = editor.GetCursor();
+	int line = editor.GetLinePos(cursor);
+	WString lineStr = editor.GetWLine(line);
+	if(cursor < lineStr.GetCount())
+		lineStr.Trim(cursor);
+	return lineStr;
+}
+
+WString TagSyntax::GetCursorLineRightSide(CodeEditor& editor) const
+{
+	int cursor = editor.GetCursor();
+	int line = editor.GetLinePos(cursor);
+	WString lineStr = editor.GetWLine(line);
+	if(cursor < lineStr.GetCount())
+		lineStr.Remove(0, cursor);
+	else
+		lineStr = "";
+	return lineStr;
+}
+
+bool TagSyntax::IsCursorInsideTag(WString& leftSide, WString& rightSide) const
+{
+	for(int i = leftSide.GetCount() - 1; i >= 0; i--) {
+		wchar c = leftSide[i];
+		
+		if(c == '>') {
+			break;
+		}
+		else
+		if(c == '<') {
+			return true;
+		}
+	}
+	
+	return false;
+}
+
 void TagSyntax::Serialize(Stream& s)
 {
 	s % hl_ink
@@ -302,4 +494,22 @@
 	  % html;
 }
 
+void TagSyntax::InitSpecialTags()
+{
+	static const char* htmlSpecialTags[] = {
+		"meta", "link",
+		"br",
+		NULL
+	};
+	
+	InitHtmlSpecialTags(htmlSpecialTags);
+}
+
+void TagSyntax::InitHtmlSpecialTags(const char* specialTags[])
+{
+	htmlSpecialTags.Clear();
+	while(*specialTags)
+		htmlSpecialTags.Add(*specialTags++);
+}
+
 END_UPP_NAMESPACE
Index: TagSyntax.h
===================================================================
--- TagSyntax.h	(wersja 9430)
+++ TagSyntax.h	(kopia robocza)
@@ -1,5 +1,12 @@
 class TagSyntax : public EditorSyntax { // Tag based languages (XML, HTML)
 public:
+	TagSyntax&  Html(bool b)                                    { html = b; return *this; }
+	TagSyntax&  Witz(bool b)                                    { witz = b; return *this; }
+	CSyntax *GetScript()                                        { return status == SCRIPT ? &script : NULL; }
+
+	TagSyntax();
+	
+public:
 	virtual void            Clear();
 	virtual void            ScanSyntax(const wchar *ln, const wchar *e, int line, int tab_size);
 	virtual void            Serialize(Stream& s);
@@ -10,7 +17,6 @@
 	virtual bool            CheckBrackets(CodeEditor& e, int& bpos0, int& bpos);
 
 private:
-
 	enum { TEXT, TAG0, TAG, ENDTAG, ATTR, COMMENT, DECL, PI, SCRIPT };
 	
 	bool    html;
@@ -22,7 +28,7 @@
 
 	CSyntax script;     // for <style> or <script>
 	enum { CSS, JS };
-	int     script_type; 
+	int     script_type;
 
 	HighlightOutput *hout;
 
@@ -35,10 +41,25 @@
 	void Put(int n = 1)                                         { Put0(hl_ink, n, hl_paper); }
 	void SetPut(int ink, int n = 1, int paper = PAPER_NORMAL)   { Set(ink, paper); Put(n); }
 
-public:
-	TagSyntax&  Html(bool b)                                    { html = b; return *this; }
-	TagSyntax&  Witz(bool b)                                    { html = b; return *this; }
-	CSyntax *GetScript()                                        { return status == SCRIPT ? &script : NULL; }
-
-	TagSyntax();
+private:
+	bool HasHtmlTags() const;
+	
+private:
+	int  GetIdentationsLevel(CodeEditor& editor) const;
+	int  GetNewIdnetations(CodeEditor& editor) const;
+	
+	Vector< Tuple2<String, int> > SplitTagsByType(const WString& str) const;
+	String                        FindTagName(const WString& str, int& i) const;
+	
+	WString GetCursorLineLeftSide(CodeEditor& editor) const;
+	WString GetCursorLineRightSide(CodeEditor& editor) const;
+	
+	bool IsCursorInsideTag(WString& leftSide, WString& rightSide) const;
+	
+private:
+	void InitSpecialTags();
+	void InitHtmlSpecialTags(const char* specialTags[]);
+	
+private:
+	Index<String> htmlSpecialTags;
 };
