Index: uppsrc/CodeEditor/CodeEditor.h
===================================================================
--- uppsrc/CodeEditor/CodeEditor.h	(revision 4204)
+++ uppsrc/CodeEditor/CodeEditor.h	(working copy)
@@ -179,7 +179,7 @@
 
 	enum {
 		HIGHLIGHT_NONE = -1, HIGHLIGHT_CPP = 0, HIGHLIGHT_USC, HIGHLIGHT_JAVA, HIGHLIGHT_T,
-		HIGHLIGHT_CALC, HIGHLIGHT_LAY, HIGHLIGHT_SCH, HIGHLIGHT_SQL,
+		HIGHLIGHT_CALC, HIGHLIGHT_LAY, HIGHLIGHT_SCH, HIGHLIGHT_SQL, HIGHLIGHT_SH,
 		HIGHLIGHT_COUNT
 	};
 
@@ -258,7 +258,7 @@
 		void  Clear();
 		bool  MatchHilite(const SyntaxState& st) const;
 		void  Grounding(const wchar *ln, const wchar *e);
-		void  ScanSyntax(const wchar *ln, const wchar *e);
+		void  ScanSyntax(const wchar *ln, const wchar *e, const int highlite = -1);
 
 		static Color IfColor(char ifstate);
 
Index: uppsrc/CodeEditor/Syntax.cpp
===================================================================
--- uppsrc/CodeEditor/Syntax.cpp	(revision 4204)
+++ uppsrc/CodeEditor/Syntax.cpp	(working copy)
@@ -116,7 +116,7 @@
 		ClearBraces();
 }
 
-void CodeEditor::SyntaxState::ScanSyntax(const wchar *ln, const wchar *e)
+void CodeEditor::SyntaxState::ScanSyntax(const wchar *ln, const wchar *e, const int highlight)
 {
 	Grounding(ln, e);
 	if(!linecont) {
@@ -138,203 +138,291 @@
 		uvscolor = c;
 		p += n;
 	}
-	if(!comment && *p == '#') {
-		while(++p < e && (*p == ' ' || *p == '\t'))
-			p++;
-		const wchar *id = p;
-		while(p < e && iscidl(*p))
-			p++;
-		int idlen = int(p - id);
-		if(id[0] == 'i' && id[1] == 'f'
-		&& (idlen == 2 || idlen == 5 && id[2] == 'd' && id[3] == 'e' && id[4] == 'f'
-		|| idlen == 6 && id[2] == 'n' && id[3] == 'd' && id[4] == 'e' && id[5] == 'f')) {
-			IfState& ifstate = ifstack.Add();
-			ifstate.state = IfState::IF;
-			ifstate.iftext = sReadLn(ln);
-			ifstate.ifline = line + 1;
+	if(highlight == HIGHLIGHT_SH) {
+		for(;;) {
+			if(p >= e) return;
+			const wchar *pp;
+			int c = *p++;
+			if(c == '#') {
+				linecomment = true;
+				return;
+			}
+			else
+			if(c == '\'' || c == '\"') {
+				p = eatstring(p - 1);
+				if(p >= e) {
+					string = true;
+					return;
+				}
+			}
+			else
+			if(c == '{') {
+				if(was_namespace) {
+					brk.Add(0);
+					was_namespace = false;
+				}
+				else {
+					cl++;
+					brk.Add('}');
+					bid.Add(lindent + 1);
+				}
+				blk.Add() = line;
+				stmtline = -1;
+				par.Clear();
+			}
+			else
+			if(c == '}') {
+				if(brk.GetCount()) {
+					if(brk.Top()) {
+						cl--;
+						if(bid.GetCount() > 1)
+							bid.Drop();
+					}
+					brk.Drop();
+				}
+				if(blk.GetCount())
+					blk.Drop();
+				stmtline = -1;
+				par.Clear();
+			}
+			else
+			if(c == '(') {
+				pl++;
+				brk.Add(')');
+				Isx& m = par.Add();
+				m.line = line;
+				m.pos = int(p - ln);
+				spar++;
+			}
+			else
+			if(c == '[') {
+				bl++;
+				brk.Add(']');
+				Isx& m = par.Add();
+				m.line = line;
+				m.pos = int(p - ln);
+				spar++;
+			}
+			else
+			if(c == ')') {
+				if(brk.GetCount()) {
+					pl--;
+					brk.Drop();
+				}
+				if(par.GetCount())
+					par.Drop();
+				spar--;
+			}
+			else
+			if(c == ']') {
+				if(brk.GetCount()) {
+					bl--;
+					brk.Drop();
+				}
+				if(par.GetCount())
+					par.Drop();
+				spar--;
+			}
 		}
-		switch(idlen)
-		{
-		case 6:
-			if(id[0] == 'd' && id[1] == 'e' && id[2] == 'f' && id[3] == 'i' && id[4] == 'n' && id[5] == 'e')
-				macro = SyntaxState::MACRO_CONT;
-			break;
-
-		case 4:
-			if(id[0] == 'e' && id[1] == 'l')
-				if(id[2] == 'i' && id[3] == 'f')
-					if(ifstack.GetCount() == 0) {
-						IfState& ifstate = ifstack.Add();
-						ifstate.ifline = 0;
-						ifstate.state = IfState::ELSE_ERROR;
-					}
-					else {
-						IfState& ifstate = ifstack.Top();
-						if(ifstate.state == IfState::IF || ifstate.state == IfState::ELIF) {
-							ifstate.state = IfState::ELIF;
-							ifstate.iftext = WString().Cat() << sReadLn(ln) << ", " << ifstate.iftext;
+	} else {
+		if(!comment && *p == '#') {
+			while(++p < e && (*p == ' ' || *p == '\t'))
+				p++;
+			const wchar *id = p;
+			while(p < e && iscidl(*p))
+				p++;
+			int idlen = int(p - id);
+			if(id[0] == 'i' && id[1] == 'f'
+			&& (idlen == 2 || idlen == 5 && id[2] == 'd' && id[3] == 'e' && id[4] == 'f'
+				|| idlen == 6 && id[2] == 'n' && id[3] == 'd' && id[4] == 'e' && id[5] == 'f')) {
+				IfState& ifstate = ifstack.Add();
+				ifstate.state = IfState::IF;
+				ifstate.iftext = sReadLn(ln);
+				ifstate.ifline = line + 1;
+			}
+			switch(idlen)
+			{
+			case 6:
+				if(id[0] == 'd' && id[1] == 'e' && id[2] == 'f' && id[3] == 'i' && id[4] == 'n' && id[5] == 'e')
+					macro = SyntaxState::MACRO_CONT;
+				break;
+	
+			case 4:
+				if(id[0] == 'e' && id[1] == 'l')
+					if(id[2] == 'i' && id[3] == 'f')
+						if(ifstack.GetCount() == 0) {
+							IfState& ifstate = ifstack.Add();
+							ifstate.ifline = 0;
+							ifstate.state = IfState::ELSE_ERROR;
 						}
-						else
+						else {
+							IfState& ifstate = ifstack.Top();
+							if(ifstate.state == IfState::IF || ifstate.state == IfState::ELIF) {
+								ifstate.state = IfState::ELIF;
+								ifstate.iftext = WString().Cat() << sReadLn(ln) << ", " << ifstate.iftext;
+							}
+							else
+								ifstate.state = IfState::ELSE_ERROR;
+						}
+					else
+					if(id[2] == 's' && id[3] == 'e')
+						if(ifstack.GetCount() == 0) {
+							IfState& ifstate = ifstack.Add();
+							ifstate.ifline = 0;
 							ifstate.state = IfState::ELSE_ERROR;
-					}
-				else
-				if(id[2] == 's' && id[3] == 'e')
-					if(ifstack.GetCount() == 0) {
+						}
+						else {
+							IfState& ifstate = ifstack.Top();
+							if(ifstate.state == IfState::IF || ifstate.state == IfState::ELIF) {
+								ifstate.state = IfState::ELSE;
+								ifstate.iftext = "#else, " + ifstate.iftext;
+							}
+							else
+								ifstate.state = IfState::ELSE_ERROR;
+						}
+				break;
+	
+			case 5:
+				if(id[0] == 'e' && id[1] == 'n' && id[2] == 'd' && id[3] == 'i' && id[4] == 'f')
+				{
+					int itop = ifstack.GetCount() - 1;
+					if(itop < 0) {
 						IfState& ifstate = ifstack.Add();
 						ifstate.ifline = 0;
-						ifstate.state = IfState::ELSE_ERROR;
+						ifstate.state = IfState::ENDIF_ERROR;
 					}
-					else {
-						IfState& ifstate = ifstack.Top();
-						if(ifstate.state == IfState::IF || ifstate.state == IfState::ELIF) {
-							ifstate.state = IfState::ELSE;
-							ifstate.iftext = "#else, " + ifstate.iftext;
-						}
-						else
-							ifstate.state = IfState::ELSE_ERROR;
-					}
-			break;
-
-		case 5:
-			if(id[0] == 'e' && id[1] == 'n' && id[2] == 'd' && id[3] == 'i' && id[4] == 'f')
-			{
-				int itop = ifstack.GetCount() - 1;
-				if(itop < 0) {
-					IfState& ifstate = ifstack.Add();
-					ifstate.ifline = 0;
-					ifstate.state = IfState::ENDIF_ERROR;
+					else if(ifstack[itop].state != IfState::ENDIF_ERROR)
+						ifstack.Trim(itop);
 				}
-				else if(ifstack[itop].state != IfState::ENDIF_ERROR)
-					ifstack.Trim(itop);
+				break;
 			}
-			break;
 		}
-	}
-	if(macro == SyntaxState::MACRO_CONT && !(p < e && e[-1] == '\\'))
-		macro = SyntaxState::MACRO_END;
-	for(;;) {
-		if(comment) {
-			p = strnext(p, e, '*');
-			if(!p) break;
-			if(*++p == '/') {
-				comment = false;
-				p++;
+		if(macro == SyntaxState::MACRO_CONT && !(p < e && e[-1] == '\\'))
+			macro = SyntaxState::MACRO_END;
+		for(;;) {
+			if(comment) {
+				p = strnext(p, e, '*');
+				if(!p) break;
+				if(*++p == '/') {
+					comment = false;
+					p++;
+				}
 			}
-		}
-		else {
-			int pc = 0;
-			for(;;) {
-				if(p >= e) return;
-				const wchar *pp;
-				if(!iscidl(pc) && (pp = isstmt(p)) != NULL) {
-					stmtline = line;
-					spar = 0;
-					pc = 0;
-					p = pp;
-				}
-				else
-				if(!iscidl(pc) && p[0] == 'n' && p[1] == 'a' && p[2] == 'm' && p[3] == 'e' &&
-				   p[4] == 's' && p[5] == 'p' && p[6] == 'a' && p[7] == 'c' && p[8] == 'e' &&
-				   !iscidl(p[9])) {
-					was_namespace = true;
-					p += 9;
-				}
-				else {
-					int c = *p++;
-					if(c == '/') break;
-					if(c == '\'' || c == '\"') {
-						p = eatstring(p - 1);
-						if(p >= e) {
-							string = true;
-							return;
-						}
+			else {
+				int pc = 0;
+				for(;;) {
+					if(p >= e) return;
+					const wchar *pp;
+					if(!iscidl(pc) && (pp = isstmt(p)) != NULL) {
+						stmtline = line;
+						spar = 0;
+						pc = 0;
+						p = pp;
 					}
 					else
-					if(c == ';' && spar == 0) {
-						seline = stmtline;
-						endstmtline = line;
-						stmtline = -1;
-						was_namespace = false;
+					if(!iscidl(pc) && p[0] == 'n' && p[1] == 'a' && p[2] == 'm' && p[3] == 'e' &&
+					   p[4] == 's' && p[5] == 'p' && p[6] == 'a' && p[7] == 'c' && p[8] == 'e' &&
+					   !iscidl(p[9])) {
+						was_namespace = true;
+						p += 9;
 					}
-					else
-					if(c == '{') {
-						if(was_namespace) {
-							brk.Add(0);
+					else {
+						int c = *p++;
+						if(c == '/') break;
+						if(c == '\'' || c == '\"') {
+							p = eatstring(p - 1);
+							if(p >= e) {
+								string = true;
+								return;
+							}
+						}
+						else
+						if(c == ';' && spar == 0) {
+							seline = stmtline;
+							endstmtline = line;
+							stmtline = -1;
 							was_namespace = false;
 						}
-						else {
-							cl++;
-							brk.Add('}');
-							bid.Add(lindent + 1);
+						else
+						if(c == '{') {
+							if(was_namespace) {
+								brk.Add(0);
+								was_namespace = false;
+							}
+							else {
+								cl++;
+								brk.Add('}');
+								bid.Add(lindent + 1);
+							}
+							blk.Add() = line;
+							stmtline = -1;
+							par.Clear();
 						}
-						blk.Add() = line;
-						stmtline = -1;
-						par.Clear();
-					}
-					else
-					if(c == '}') {
-						if(brk.GetCount()) {
-							if(brk.Top()) {
-								cl--;
-								if(bid.GetCount() > 1)
-									bid.Drop();
+						else
+						if(c == '}') {
+							if(brk.GetCount()) {
+								if(brk.Top()) {
+									cl--;
+									if(bid.GetCount() > 1)
+										bid.Drop();
+								}
+								brk.Drop();
 							}
-							brk.Drop();
+							if(blk.GetCount())
+								blk.Drop();
+							stmtline = -1;
+							par.Clear();
 						}
-						if(blk.GetCount())
-							blk.Drop();
-						stmtline = -1;
-						par.Clear();
-					}
-					else
-					if(c == '(') {
-						pl++;
-						brk.Add(')');
-						Isx& m = par.Add();
-						m.line = line;
-						m.pos = int(p - ln);
-						spar++;
-					}
-					else
-					if(c == '[') {
-						bl++;
-						brk.Add(']');
-						Isx& m = par.Add();
-						m.line = line;
-						m.pos = int(p - ln);
-						spar++;
-					}
-					else
-					if(c == ')') {
-						if(brk.GetCount()) {
-							pl--;
-							brk.Drop();
+						else
+						if(c == '(') {
+							pl++;
+							brk.Add(')');
+							Isx& m = par.Add();
+							m.line = line;
+							m.pos = int(p - ln);
+							spar++;
 						}
-						if(par.GetCount())
-							par.Drop();
-						spar--;
-					}
-					else
-					if(c == ']') {
-						if(brk.GetCount()) {
-							bl--;
-							brk.Drop();
+						else
+						if(c == '[') {
+							bl++;
+							brk.Add(']');
+							Isx& m = par.Add();
+							m.line = line;
+							m.pos = int(p - ln);
+							spar++;
 						}
-						if(par.GetCount())
-							par.Drop();
-						spar--;
+						else
+						if(c == ')') {
+							if(brk.GetCount()) {
+								pl--;
+								brk.Drop();
+							}
+							if(par.GetCount())
+								par.Drop();
+							spar--;
+						}
+						else
+						if(c == ']') {
+							if(brk.GetCount()) {
+								bl--;
+								brk.Drop();
+							}
+							if(par.GetCount())
+								par.Drop();
+							spar--;
+						}
+						pc = c;
 					}
-					pc = c;
 				}
+				if(*p == '/') {
+					linecomment = true;
+					return;
+				}
+				if(*p == '*') {
+					comment = true;
+					p++;
+				}
 			}
-			if(*p == '/') {
-				linecomment = true;
-				return;
-			}
-			if(*p == '*') {
-				comment = true;
-				p++;
-			}
 		}
 	}
 }
@@ -353,7 +441,7 @@
 		if(st.macro != SyntaxState::MACRO_CONT)
 			st.macro = SyntaxState::MACRO_OFF;
 		WString l = GetWLine(st.line);
-		st.ScanSyntax(l, l.End());
+		st.ScanSyntax(l, l.End(), highlight);
 		st.line++;
 		static int d[] = { 0, 100, 2000 };
 		for(int i = 0; i < 3; i++)
Index: uppsrc/CodeEditor/Highlight.cpp
===================================================================
--- uppsrc/CodeEditor/Highlight.cpp	(revision 4204)
+++ uppsrc/CodeEditor/Highlight.cpp	(working copy)
@@ -180,7 +180,12 @@
 			}
 		}
 		else
-		if(*p == '%')
+		if(*p == '$' && delim != '\'' && highlight == HIGHLIGHT_SH) {
+			const wchar *t = p++;
+			while(IsAlNum(*p) || *p == '_') p++;
+			hls.Put(int(p - t), hl_style[INK_MACRO]); //beter ink??  ---Honza
+		} else
+		if(*p == '%' && highlight != HIGHLIGHT_SH)
 			if(p[1] == '%') {
 				hls.Put(2, hl_style[INK_CONST_STRING]);
 				p += 2;
@@ -377,6 +382,12 @@
 			"LAYOUT", "ITEM", "UNTYPED", "END_LAYOUT",
 			NULL
 		};
+		static const char *sh[] = {
+			"break", "case", "continue", "do", "done", "elif", "else", "esac", "eval", "exit",
+			"export", "fi", "for", "function", "goto", "if", "in", "integer", "return", "set",
+			"shift", "then", "until", "while",
+			NULL
+		};
 		static const char *sch[] = {
 			"BIT", "BIT_ARRAY", "BIT_", "BIT_ARRAY_",
 			"BOOL", "BOOL_ARRAY", "BOOL_", "BOOL_ARRAY_",
@@ -416,10 +427,10 @@
 			NULL
 		};
 		static const char **kw[HIGHLIGHT_COUNT] = {
-			cpp, usc, java, tfile, usc, lay, sch, sql
+			cpp, usc, java, tfile, usc, lay, sch, sql, sh
 		};
 		static const char **nm[HIGHLIGHT_COUNT] = {
-			upp, usclib, javan, tlng, usclib, javan, javan, javan
+			upp, usclib, javan, tlng, usclib, javan, javan, javan, javan
 		};
 		const char **q = NULL;
 		for(int i = 0; i < HIGHLIGHT_COUNT; i++) {
@@ -484,7 +495,7 @@
 			p++;
 			hls.Put(hl_style[INK_NORMAL]);
 		}
-		if(*p == '#') {
+		if(*p == '#' && highlight != HIGHLIGHT_SH) {
 			static const char *pd[] = {
 				"define", "error", "if", "elif", "else", "endif",
 				"ifdef", "ifndef", "include", "line", "undef", "pragma",
@@ -513,7 +524,8 @@
 	bool is_comment = false;
 	while(p < e) {
 		int pair = MAKELONG(p[0], p[1]);
-		if(ss.linecomment && ss.linecont || pair == MAKELONG('/', '/')) {
+		if(ss.linecomment && ss.linecont || 
+		   highlight == HIGHLIGHT_SH ? (p[0] == '#') : (pair == MAKELONG('/', '/'))) {
 			hls.Put(text.GetLength() + 1 - hls.pos, hl_style[INK_COMMENT]);
 			is_comment = true;
 			break;
@@ -597,6 +609,12 @@
 			hls.Put(int(p - t), hl_style[INK_CONST_HEX]);
 		}
 		else
+		if(*p == '$' && highlight == HIGHLIGHT_SH) {
+			const wchar *t = p++;
+			while(IsAlNum(*p) || *p == '_') p++;
+			hls.Put(int(p - t), hl_style[INK_MACRO]); //beter ink??  ---Honza
+		}
+		else
 		if(IsDigit(*p)) {
 			const wchar *t = p;
 			int c = INK_CONST_INT;
Index: uppsrc/ide/idefile.cpp
===================================================================
--- uppsrc/ide/idefile.cpp	(revision 4204)
+++ uppsrc/ide/idefile.cpp	(working copy)
@@ -28,6 +28,9 @@
 		if(ext == ".lay")
 			editor.Highlight(CodeEditor::HIGHLIGHT_LAY);
 		else
+		if(ext == ".sh")
+			editor.Highlight(CodeEditor::HIGHLIGHT_SH);
+		else
 		if(ext == ".sch")
 			editor.Highlight(CodeEditor::HIGHLIGHT_SCH);
 		else
@@ -46,6 +49,9 @@
 		if(hl == "java")
 			editor.Highlight(CodeEditor::HIGHLIGHT_JAVA);
 		else
+		if(hl == "sh")
+			editor.Highlight(CodeEditor::HIGHLIGHT_SH);
+		else
 			editor.Highlight(CodeEditor::HIGHLIGHT_NONE);
 	}
 }
@@ -132,6 +138,7 @@
 	d.highlight.Add("cpp", "C++");
 	d.highlight.Add("java", "Java");
 	d.highlight.Add("esc", "Esc");
+	d.highlight.Add("sh", "Shell");
 	d.tabsize <<= f.tabsize > 0 ? f.tabsize : Null;
 	d.tabsize <<= d.Breaker(111);
 	d.tabsize.MinMax(1, 100);
