/uppsrc/CodeEditor/TagSyntax.cpp

https://github.com/ultimatepp/mirror · C++ · 300 lines · 282 code · 18 blank · 0 comment · 120 complexity · 49f35efa1030af5e7b0151672a382819 MD5 · raw file

  1. #include "CodeEditor.h"
  2. namespace Upp {
  3. TagSyntax::TagSyntax()
  4. {
  5. Clear();
  6. hout = NULL;
  7. html = true;
  8. witz = false;
  9. }
  10. void TagSyntax::Clear()
  11. {
  12. hl_ink = INK_NORMAL;
  13. hl_paper = PAPER_NORMAL;
  14. status = TEXT;
  15. }
  16. void TagSyntax::Put0(int ink, int n, int paper)
  17. {
  18. if(hout)
  19. hout->Put(n, hl_style[ink], hl_style[paper]);
  20. }
  21. const wchar *TagSyntax::Spaces(const wchar *s, const wchar *e)
  22. {
  23. while(s < e && IsSpace(*s)) {
  24. s++;
  25. Put();
  26. }
  27. return s;
  28. }
  29. void TagSyntax::DoScript(const wchar *s, const wchar *e, CodeEditor *editor, int line, int tabsize, int64 pos)
  30. {
  31. if(hout)
  32. script.Highlight(s, e, *hout, editor, line, pos);
  33. else
  34. script.ScanSyntax(s, e, line, tabsize);
  35. }
  36. inline
  37. static const wchar *sSkipSpaces(const wchar *s, const wchar *e)
  38. {
  39. while(s < e && IsSpace(*s))
  40. s++;
  41. return s;
  42. }
  43. inline bool cmp_wi(const wchar *s, const wchar *t, int len)
  44. {
  45. while(len--) {
  46. if(ToUpper(*s++) != ToUpper(*t++))
  47. return false;
  48. }
  49. return true;
  50. }
  51. inline
  52. bool IsEndTag(const wchar *s, const wchar *e, const wchar *tag, int len)
  53. {
  54. if(*s != '<' || s >= e)
  55. return false;
  56. s = sSkipSpaces(s + 1, e);
  57. if(*s != '/' || s >= e)
  58. return false;
  59. s = sSkipSpaces(s + 1, e);
  60. return s < e && e - s >= len && cmp_wi(s, tag, len);
  61. }
  62. const wchar *IsScriptEnd(const wchar *s, const wchar *e, bool script)
  63. {
  64. while(s < e) {
  65. int c = *s;
  66. if(c == '\"' || c == '\'') {
  67. s++;
  68. while(s < e && *s != c) {
  69. if(*s == '\\' && s + 1 < e)
  70. s += 2;
  71. else
  72. s++;
  73. }
  74. }
  75. else {
  76. static WString s_script("script");
  77. static WString s_style("style");
  78. const WString& tag = script ? s_script : s_style;
  79. if(IsEndTag(s, e, ~tag, tag.GetLength()))
  80. return s;
  81. }
  82. s++;
  83. }
  84. return NULL;
  85. }
  86. void TagSyntax::Do(const wchar *s, const wchar *e, CodeEditor *editor, int line, int tabsize, int64 pos)
  87. {
  88. doscript:
  89. if(status == SCRIPT) {
  90. const wchar *q = IsScriptEnd(s, e, script_type == JS);
  91. if(q) {
  92. DoScript(s, q, editor, line, tabsize, pos);
  93. s = q;
  94. status = TEXT;
  95. Set(INK_NORMAL);
  96. }
  97. else {
  98. DoScript(s, e, editor, line, tabsize, pos);
  99. return;
  100. }
  101. }
  102. while(s < e) {
  103. s = Spaces(s, e);
  104. if(s >= e)
  105. break;
  106. if(status == COMMENT) {
  107. if(s + 2 < e && s[0] == '-' && s[1] == '-' && s[2] == '>') {
  108. SetPut(INK_COMMENT, 3);
  109. s += 3;
  110. status = TEXT;
  111. Set(INK_NORMAL);
  112. }
  113. else {
  114. Put();
  115. s++;
  116. }
  117. }
  118. else
  119. if(*s == '&') {
  120. s++;
  121. Put0(INK_CONST_STRING, 1);
  122. while(s < e && *s != ';') {
  123. Put0(INK_CONST_STRING, 1);
  124. s++;
  125. }
  126. }
  127. else
  128. if(*s == '<') {
  129. tagname.Clear();
  130. s++;
  131. if(s + 2 < e && s[0] == '!' && s[1] == '-' && s[2] == '-') {
  132. SetPut(INK_COMMENT, 4);
  133. s += 3;
  134. status = COMMENT;
  135. }
  136. else
  137. if(*s == '!') {
  138. status = DECL;
  139. s++;
  140. SetPut(INK_MACRO, 2, PAPER_MACRO);
  141. }
  142. else
  143. if(*s == '?') {
  144. status = PI;
  145. s++;
  146. SetPut(INK_IFDEF, 2, PAPER_IFDEF);
  147. }
  148. else {
  149. status = TAG0;
  150. SetPut(INK_KEYWORD);
  151. }
  152. }
  153. else
  154. if(*s == '>') {
  155. s++;
  156. Put();
  157. Set(INK_NORMAL);
  158. status = TEXT;
  159. if(html) {
  160. if(tagname == "script") {
  161. script.SetHighlight(CSyntax::HIGHLIGHT_JAVASCRIPT);
  162. status = SCRIPT;
  163. script_type = JS;
  164. goto doscript;
  165. }
  166. else
  167. if(tagname == "style") {
  168. script.SetHighlight(CSyntax::HIGHLIGHT_CSS);
  169. status = SCRIPT;
  170. script_type = CSS;
  171. goto doscript;
  172. }
  173. }
  174. }
  175. else
  176. if(status == TAG0) {
  177. tagname.Clear();
  178. while(s < e && !IsSpace(*s) && *s != '>') {
  179. tagname.Cat(*s++);
  180. Put();
  181. }
  182. if(*tagname == '/')
  183. status = ENDTAG;
  184. else
  185. status = TAG;
  186. }
  187. else
  188. if(status == TAG) {
  189. int n = 0;
  190. while(s < e && !IsSpace(*s) && *s != '>' && *s != '=') {
  191. n++;
  192. s++;
  193. }
  194. Put0(INK_UPP, n);
  195. status = ATTR;
  196. }
  197. else
  198. if(status == ATTR) {
  199. if(*s == '=') {
  200. s++;
  201. Put0(INK_UPP);
  202. }
  203. s = Spaces(s, e);
  204. int c = *s;
  205. if(c == '\"' || c == '\'') {
  206. int n = 1;
  207. s++;
  208. while(s < e) {
  209. n++;
  210. if(*s++ == c)
  211. break;
  212. }
  213. Put0(INK_CONST_STRING, n);
  214. }
  215. else {
  216. int n = 0;
  217. while(s < e && !IsSpace(*s) && *s != '>') {
  218. s++;
  219. n++;
  220. }
  221. Put0(INK_CONST_FLOAT, n);
  222. }
  223. status = TAG;
  224. }
  225. else {
  226. s++;
  227. Put();
  228. }
  229. }
  230. }
  231. void TagSyntax::CheckSyntaxRefresh(CodeEditor& e, int64 pos, const WString& text)
  232. {
  233. script.CheckSyntaxRefresh(e, pos, text);
  234. for(const wchar *s = text; *s; s++)
  235. if(*s == '<' || *s == '>' || *s == '/') {
  236. e.Refresh();
  237. return;
  238. }
  239. int64 l = max(pos - 6, (int64)0);
  240. int64 h = min(pos + text.GetLength() + 6, e.GetLength64());
  241. if(h - l > 200) {
  242. e.Refresh();
  243. return;
  244. }
  245. WString w = ToLower(e.GetW(l, e.LimitSize(h - l)));
  246. if(w.Find("style") >= 0 || w.Find("script") >= 0)
  247. e.Refresh();
  248. }
  249. void TagSyntax::ScanSyntax(const wchar *s, const wchar *e, int line, int tabsize)
  250. {
  251. Do(s, e, NULL, line, tabsize, 0);
  252. }
  253. void TagSyntax::Highlight(const wchar *s, const wchar *end, HighlightOutput& hls, CodeEditor *editor, int line, int64 pos)
  254. {
  255. hout = &hls;
  256. Do(s, end, editor, line, editor ? editor->GetTabSize() : 4, pos);
  257. hout = NULL;
  258. }
  259. void TagSyntax::IndentInsert(CodeEditor& editor, int chr, int count)
  260. {
  261. if(status == SCRIPT)
  262. script.IndentInsert(editor, chr, count);
  263. else
  264. editor.InsertChar(chr, count);
  265. }
  266. bool TagSyntax::CheckBrackets(CodeEditor& e, int64& bpos0, int64& bpos)
  267. {
  268. if(status == SCRIPT)
  269. return script.CheckBrackets(e, bpos0, bpos);
  270. return false;
  271. }
  272. void TagSyntax::Serialize(Stream& s)
  273. {
  274. s % hl_ink
  275. % hl_paper
  276. % status
  277. % tagname
  278. % script
  279. % script_type
  280. % html;
  281. }
  282. }