From b813e3ce92a47ca2c9274e90b92c0b83f250d25c Mon Sep 17 00:00:00 2001 From: cxl Date: Mon, 19 May 2014 18:17:40 +0000 Subject: [PATCH] ide: HTML/XML highlightitinh finalized git-svn-id: svn://ultimatepp.org/upp/trunk@7390 f0d560ea-af0d-0410-9eb7-867de7ffcac7 --- uppsrc/CodeEditor/CLogic.cpp | 11 ++ uppsrc/CodeEditor/CRegister.icpp | 8 +- uppsrc/CodeEditor/CSyntax.h | 1 + uppsrc/CodeEditor/CodeEditor.cpp | 22 +-- uppsrc/CodeEditor/CodeEditor.h | 4 +- uppsrc/CodeEditor/CodeEditor.upp | 6 +- uppsrc/CodeEditor/Syntax.cpp | 4 + uppsrc/CodeEditor/Syntax.h | 1 + .../{XmlSyntax.cpp => TagSyntax.cpp} | 140 ++++++++++++++---- .../CodeEditor/{XmlSyntax.h => TagSyntax.h} | 16 +- 10 files changed, 157 insertions(+), 56 deletions(-) rename uppsrc/CodeEditor/{XmlSyntax.cpp => TagSyntax.cpp} (51%) rename uppsrc/CodeEditor/{XmlSyntax.h => TagSyntax.h} (65%) diff --git a/uppsrc/CodeEditor/CLogic.cpp b/uppsrc/CodeEditor/CLogic.cpp index ce30639b9..402a6405d 100644 --- a/uppsrc/CodeEditor/CLogic.cpp +++ b/uppsrc/CodeEditor/CLogic.cpp @@ -182,4 +182,15 @@ Vector CSyntax::PickIfStack() return pick(ifstack); } +void CSyntax::CheckSyntaxRefresh(CodeEditor& e, int pos, const WString& text) +{ + for(const wchar *s = text; *s; s++) { + if(*s == '{' || *s == '(' || *s == '[' || *s == '/' || *s == '*' || + *s == '}' || *s == ')' || *s == ']' || *s == '\\') { + e.Refresh(); + break; + } + } +} + END_UPP_NAMESPACE diff --git a/uppsrc/CodeEditor/CRegister.icpp b/uppsrc/CodeEditor/CRegister.icpp index 3d198fdc3..825eda315 100644 --- a/uppsrc/CodeEditor/CRegister.icpp +++ b/uppsrc/CodeEditor/CRegister.icpp @@ -13,9 +13,9 @@ void RegisterCSyntax(const char *id, int kind, EditorSyntax::Register(id, callback1(CreateCSyntax, kind), exts, description); } -void CreateTagSyntax(One& e) +void CreateTagSyntax(One& e, bool html) { - e.Create(); + e.Create().Html(html); } INITBLOCK { @@ -34,8 +34,8 @@ INITBLOCK { RegisterCSyntax("usc", CSyntax::HIGHLIGHT_USC, "*.usc", "U++ widget definitions (.usc)"); RegisterCSyntax("calc", CSyntax::HIGHLIGHT_CALC, "", ""); - EditorSyntax::Register("xml", callback(CreateTagSyntax), "*.xml", "XML (.xml)"); - EditorSyntax::Register("html", callback(CreateTagSyntax), "*.html *.htm", "HTML (.html)"); + EditorSyntax::Register("xml", callback1(CreateTagSyntax, false), "*.xml", "XML (.xml)"); + EditorSyntax::Register("html", callback1(CreateTagSyntax, true), "*.html *.htm", "HTML (.html)"); } END_UPP_NAMESPACE diff --git a/uppsrc/CodeEditor/CSyntax.h b/uppsrc/CodeEditor/CSyntax.h index f43e9b74e..a711bbd90 100644 --- a/uppsrc/CodeEditor/CSyntax.h +++ b/uppsrc/CodeEditor/CSyntax.h @@ -8,6 +8,7 @@ public: virtual bool CanAssist() const; virtual void Highlight(const wchar *s, const wchar *end, HighlightOutput& hls, CodeEditor *editor, int line, int pos); + virtual void CheckSyntaxRefresh(CodeEditor& e, int pos, const WString& text); virtual Vector PickIfStack(); // TODO: Refactor? private: diff --git a/uppsrc/CodeEditor/CodeEditor.cpp b/uppsrc/CodeEditor/CodeEditor.cpp index a0bf7b301..eec4509ba 100644 --- a/uppsrc/CodeEditor/CodeEditor.cpp +++ b/uppsrc/CodeEditor/CodeEditor.cpp @@ -75,32 +75,32 @@ inline bool RBR(int c) { return isbrkt(c); } -void CodeEditor::CheckBraces(const WString& text) +void CodeEditor::CheckSyntaxRefresh(int pos, const WString& text) { - for(const wchar *s = text; *s; s++) - if(*s == '{' || *s == '(' || *s == '[' || *s == '/' || *s == '*' || - *s == '}' || *s == ')' || *s == ']' || *s == '\\') { - Refresh(); - break; - } + GetSyntax(GetLine(pos))->CheckSyntaxRefresh(*this, pos, text); } void CodeEditor::PostInsert(int pos, const WString& text) { if(check_edited) bar.SetEdited(GetLine(pos)); if(IsFullRefresh()) return; - if(text.GetCount() > 200) + if(text.GetCount() > 200 || text.Find('\n') >= 0) Refresh(); else - CheckBraces(text); + CheckSyntaxRefresh(pos, text); } void CodeEditor::PreRemove(int pos, int size) { if(IsFullRefresh()) return; if(size > 200) Refresh(); - else - CheckBraces(GetW(pos, size)); + else { + WString text = GetW(pos, size); + if(text.Find('\n') >= 0) + Refresh(); + else + CheckSyntaxRefresh(pos, text); + } } void CodeEditor::PostRemove(int pos, int size) { diff --git a/uppsrc/CodeEditor/CodeEditor.h b/uppsrc/CodeEditor/CodeEditor.h index 8e5adf074..67797282f 100644 --- a/uppsrc/CodeEditor/CodeEditor.h +++ b/uppsrc/CodeEditor/CodeEditor.h @@ -169,7 +169,7 @@ struct FindReplaceDlg : WithIDEFindReplaceLayout { #include "Syntax.h" #include "CSyntax.h" -#include "XmlSyntax.h" +#include "TagSyntax.h" class CodeEditor : public LineEdit, public HighlightSetup //TODO:SYNTAX @@ -280,7 +280,7 @@ protected: void FindWildcard(); void ReplaceWildcard(); void InsertWildcard(int c); - void CheckBraces(const WString& text); + void CheckSyntaxRefresh(int pos, const WString& text); void SetFound(int fi, int type, const WString& text); diff --git a/uppsrc/CodeEditor/CodeEditor.upp b/uppsrc/CodeEditor/CodeEditor.upp index 868053469..b80a1b5bc 100644 --- a/uppsrc/CodeEditor/CodeEditor.upp +++ b/uppsrc/CodeEditor/CodeEditor.upp @@ -21,9 +21,9 @@ file CHighlight.cpp, CLogic.cpp, CRegister.icpp, - Xml readonly separator, - XmlSyntax.h, - XmlSyntax.cpp, + TagSyntax readonly separator, + TagSyntax.h, + TagSyntax.cpp, Editor readonly separator, EditorBar.cpp, FindReplace.cpp, diff --git a/uppsrc/CodeEditor/Syntax.cpp b/uppsrc/CodeEditor/Syntax.cpp index 1044a51e2..edfc4672e 100644 --- a/uppsrc/CodeEditor/Syntax.cpp +++ b/uppsrc/CodeEditor/Syntax.cpp @@ -50,6 +50,10 @@ Color EditorSyntax::IfColor(char c) } } +void EditorSyntax::CheckSyntaxRefresh(CodeEditor& e, int pos, const WString& text) +{ +} + EditorSyntax::~EditorSyntax() {} END_UPP_NAMESPACE diff --git a/uppsrc/CodeEditor/Syntax.h b/uppsrc/CodeEditor/Syntax.h index 1d16e39a1..6f651ff55 100644 --- a/uppsrc/CodeEditor/Syntax.h +++ b/uppsrc/CodeEditor/Syntax.h @@ -101,6 +101,7 @@ public: virtual void Serialize(Stream& s); virtual void IndentInsert(CodeEditor& editor, int chr, int count); virtual bool CheckBrackets(CodeEditor& e, int& bpos0, int& bpos); // TODO: Replace with generic mechanism + virtual void CheckSyntaxRefresh(CodeEditor& e, int pos, const WString& text); virtual bool CanAssist() const; virtual void Highlight(const wchar *s, const wchar *end, HighlightOutput& hls, CodeEditor *editor, int line, int pos); diff --git a/uppsrc/CodeEditor/XmlSyntax.cpp b/uppsrc/CodeEditor/TagSyntax.cpp similarity index 51% rename from uppsrc/CodeEditor/XmlSyntax.cpp rename to uppsrc/CodeEditor/TagSyntax.cpp index c85c8dd17..a3a194f2d 100644 --- a/uppsrc/CodeEditor/XmlSyntax.cpp +++ b/uppsrc/CodeEditor/TagSyntax.cpp @@ -2,13 +2,13 @@ NAMESPACE_UPP -void XmlSyntax::Clear() +void TagSyntax::Clear() { hl_ink = INK_NORMAL; hl_paper = PAPER_NORMAL; } -void XmlSyntax::Put0(int ink, int n, int paper) +void TagSyntax::Put0(int ink, int n, int paper) { if(hout) hout->Put(n, hl_style[ink], hl_style[paper]); @@ -19,7 +19,7 @@ inline static bool IsXmlNameChar(int c) return IsAlNum(c) || c == '.' || c == '-' || c == '_' || c == ':'; } -const wchar *XmlSyntax::Spaces(const wchar *s, const wchar *e) +const wchar *TagSyntax::Spaces(const wchar *s, const wchar *e) { while(s < e && IsSpace(*s)) { s++; @@ -28,7 +28,7 @@ const wchar *XmlSyntax::Spaces(const wchar *s, const wchar *e) return s; } -void XmlSyntax::DoScript(const wchar *s, const wchar *e) +void TagSyntax::DoScript(const wchar *s, const wchar *e) { if(hout) script.Highlight(s, e, *hout, NULL, 0, 0); @@ -36,25 +36,75 @@ void XmlSyntax::DoScript(const wchar *s, const wchar *e) script.ScanSyntax(s, e, 0, 0); } -void XmlSyntax::Do(const wchar *s, const wchar *e) +inline +static const wchar *sSkipSpaces(const wchar *s, const wchar *e) +{ + while(s < e && IsSpace(*s)) + s++; + return s; +} + +inline bool cmp_wi(const wchar *s, const wchar *t, int len) +{ + while(len--) { + if(ToUpper(*s++) != ToUpper(*t++)) + return false; + } + return true; +} + +inline +bool IsEndTag(const wchar *s, const wchar *e, const wchar *tag, int len) +{ + if(*s != '<' || s >= e) + return false; + s = sSkipSpaces(s + 1, e); + if(*s != '/' || s >= e) + return false; + s = sSkipSpaces(s + 1, e); + return s < e && e - s >= len && cmp_wi(s, tag, len); +} + +const wchar *IsScriptEnd(const wchar *s, const wchar *e, bool script) +{ + while(s < e) { + int c = *s; + if(c == '\"' || c == '\'') { + s++; + while(s < e && *s != c) { + if(*s == '\\' && s + 1 < e) + s += 2; + else + s++; + } + } + else { + static WString s_script("script"); + static WString s_style("style"); + const WString& tag = script ? s_script : s_style; + if(IsEndTag(s, e, ~tag, tag.GetLength())) + return s; + } + s++; + } + return NULL; +} + +void TagSyntax::Do(const wchar *s, const wchar *e) { doscript: if(status == SCRIPT) { // TODO: Improve ending detection... - static WString h1 = ""; - static WString h2 = ""; - int q = find(s, e - s, ~h1, h1.GetLength(), 0); - if(q < 0) - q = find(s, e - s, ~h2, h2.GetLength(), 0); - if(q < 0) { - DoScript(s, e); - return; - } - else { - DoScript(s, s + q); - s += q; + const wchar *q = IsScriptEnd(s, e, script_type == JS); + if(q) { + DoScript(s, q); + s = q; status = TEXT; Set(INK_NORMAL); } + else { + DoScript(s, e); + return; + } } while(s < e) { s = Spaces(s, e); @@ -113,15 +163,20 @@ doscript: Put(); Set(INK_NORMAL); status = TEXT; - if(tagname == "script") { - script.SetHighlight(CSyntax::HIGHLIGHT_JAVASCRIPT); - status = SCRIPT; - goto doscript; - } - if(tagname == "style") { - script.SetHighlight(CSyntax::HIGHLIGHT_CSS); - status = SCRIPT; - goto doscript; + if(html) { + if(tagname == "script") { + script.SetHighlight(CSyntax::HIGHLIGHT_JAVASCRIPT); + status = SCRIPT; + script_type = JS; + goto doscript; + } + else + if(tagname == "style") { + script.SetHighlight(CSyntax::HIGHLIGHT_CSS); + status = SCRIPT; + script_type = CSS; + goto doscript; + } } } else @@ -131,7 +186,9 @@ doscript: tagname.Cat(*s++); Put(); } - if(*tagname != '/') + if(*tagname == '/') + status = ENDTAG; + else status = TAG; } else @@ -179,25 +236,46 @@ doscript: } } -void XmlSyntax::ScanSyntax(const wchar *s, const wchar *e, int, int) +void TagSyntax::CheckSyntaxRefresh(CodeEditor& e, int pos, const WString& text) +{ + script.CheckSyntaxRefresh(e, pos, text); + for(const wchar *s = text; *s; s++) + if(*s == '<' || *s == '>' || *s == '/') { + e.Refresh(); + return; + } + int l = max(pos - 6, 0); + int h = min(pos + text.GetLength() + 6, e.GetLength()); + if(h - l > 200) { + e.Refresh(); + return; + } + WString w = ToLower(e.GetW(l, h - l)); + if(w.Find("style") >= 0 || w.Find("script") >= 0) + e.Refresh(); +} + +void TagSyntax::ScanSyntax(const wchar *s, const wchar *e, int, int) { Do(s, e); } -void XmlSyntax::Highlight(const wchar *s, const wchar *end, HighlightOutput& hls, CodeEditor *editor, int line, int pos) +void TagSyntax::Highlight(const wchar *s, const wchar *end, HighlightOutput& hls, CodeEditor *editor, int line, int pos) { hout = &hls; Do(s, end); hout = NULL; } -void XmlSyntax::Serialize(Stream& s) +void TagSyntax::Serialize(Stream& s) { s % hl_ink % hl_paper % status % tagname - % script; + % script + % script_type + % html; } END_UPP_NAMESPACE diff --git a/uppsrc/CodeEditor/XmlSyntax.h b/uppsrc/CodeEditor/TagSyntax.h similarity index 65% rename from uppsrc/CodeEditor/XmlSyntax.h rename to uppsrc/CodeEditor/TagSyntax.h index d1d0abc35..ae21716b3 100644 --- a/uppsrc/CodeEditor/XmlSyntax.h +++ b/uppsrc/CodeEditor/TagSyntax.h @@ -1,21 +1,25 @@ -class XmlSyntax : public EditorSyntax { // Tag based languages (XML, HTML) +class TagSyntax : public EditorSyntax { // Tag based languages (XML, HTML) public: virtual void Clear(); virtual void ScanSyntax(const wchar *ln, const wchar *e, int line, int tab_size); virtual void Serialize(Stream& s); virtual void Highlight(const wchar *s, const wchar *end, HighlightOutput& hls, CodeEditor *editor, int line, int pos); + virtual void CheckSyntaxRefresh(CodeEditor& e, int pos, const WString& text); private: - enum { TEXT, TAG0, TAG, ATTR, COMMENT, DECL, PI, SCRIPT }; + enum { TEXT, TAG0, TAG, ENDTAG, ATTR, COMMENT, DECL, PI, SCRIPT }; + bool html; int status; int hl_ink; int hl_paper; String tagname; - - CSyntax script; + + CSyntax script; // for