Index: CodeEditor.h
===================================================================
--- CodeEditor.h	(wersja 9430)
+++ CodeEditor.h	(kopia robocza)
@@ -141,6 +141,31 @@
 	virtual ~EditorBar();
 };
 
+class Ident {
+public:
+	enum Type {
+		Tab = 0,
+		Space,
+		Unknown
+	};
+
+public:
+	static Type FindType(CodeEditor& editor);
+	static Type FindType(const WString& line);
+	static Type FindType(const WString& line, CodeEditor& editor);
+	static int  FindSize(const WString& line, Ident::Type type);
+	static int  FindSpaceSize(CodeEditor& editor);
+	
+	static char   GetChar(Ident::Type type);
+	static String GetString(Ident::Type type, int identLevel = 1);
+	
+private:
+	Ident();
+	Ident(const Ident&);
+	Ident& operator=(Ident&);
+	~Ident();
+};
+
 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,10 +38,13 @@
 	EditorBar.cpp,
 	FindReplace.cpp,
 	Lang.cpp,
+	Indent.cpp,
 	CodeEditor.cpp,
 	CodeEditor.lay,
 	CodeEditor.iml,
 	CodeEditor.t,
+	Indent readonly separator,
+	Indent.h,
 	Info readonly separator,
 	Copying;
 
Index: PythonSyntax.cpp
===================================================================
--- PythonSyntax.cpp	(wersja 9430)
+++ PythonSyntax.cpp	(kopia robocza)
@@ -70,17 +70,17 @@
 {
 	if(chr == '\n') {
 		while(count--) {
-			WString cursorLine = editor.GetWLine(editor.GetCursorLine());
+			WString cline = editor.GetWLine(editor.GetCursorLine());
 			editor.InsertChar('\n', 1);
 			
-			Identation::Type idType = FindIdentationType(editor, cursorLine);
-			char idChar = GetIdentationByType(idType);
+			Ident::Type identType = Ident::FindType(cline, editor);
+			char identChar = Ident::GetChar(identType);
 			int mult = 1;
-			if(idType == Identation::Space)
-				mult = CalculateSpaceIndetationSize(editor);
-			if(LineHasColon(cursorLine))
-				editor.InsertChar(idChar, mult);
-			editor.InsertChar(idChar, CalculateLineIndetations(cursorLine, idType));
+			if(identType == Ident::Space)
+				mult = Ident::FindSpaceSize(editor);
+			if(LineHasColon(cline))
+				editor.InsertChar(identChar, mult);
+			editor.InsertChar(identChar, Ident::FindSize(cline, identType));
 		}
 	}
 	if(count > 0)
@@ -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)
@@ -26,10 +26,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;
+	}
+	
+	if(chr == '\n') {
+		while(count--) {
+			WString line = editor.GetWLine(editor.GetCursorLine());
+			Ident::Type type = Ident::FindType(line);
+			
+			int currentLevel = Ident::FindSize(line, type);
+			int newLevel = GetNewIdnetations(editor);
+			int wholeLevel = currentLevel + newLevel;
+			
+			String afterCursor;
+			if(newLevel > 0) {
+				WString rightSide = GetCursorRightSide(editor);
+				if(rightSide.StartsWith("<")) {
+					afterCursor = "\n";
+					for(int i = 0; i < wholeLevel - 1; i++)
+						afterCursor += Ident::GetString(type);
+				}
+				else
+				if(!rightSide.IsEmpty()) {
+					wholeLevel = 0;
+				}
+			}
+			
+			editor.InsertChar('\n', 1);
+			editor.InsertChar('\t', wholeLevel);
+			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 = GetCursorLeftSide(editor);
+	WString rightSide = GetCursorRightSide(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::GetCursorLeftSide(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::GetCursorRightSide(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,23 @@
 	  % 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 GetCursorLeftSide(CodeEditor& editor) const;
+	WString GetCursorRightSide(CodeEditor& editor) const;
+	
+	bool IsCursorInsideTag(WString& leftSide, WString& rightSide) const;
+	
+private:
+	void InitSpecialTags();
+	void InitHtmlSpecialTags(const char* specialTags[]);
+	
+private:
+	Index<String> htmlSpecialTags;
 };
