SyntaxHighlighting.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. 
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text.RegularExpressions;
  6. using Terminal.Gui;
  7. using Attribute = Terminal.Gui.Attribute;
  8. namespace UICatalog.Scenarios {
  9. [ScenarioMetadata (Name: "Syntax Highlighting", Description: "Text editor with keyword highlighting using the TextView control.")]
  10. [ScenarioCategory ("Text and Formatting")]
  11. [ScenarioCategory ("Controls")]
  12. [ScenarioCategory ("TextView")]
  13. public class SyntaxHighlighting : Scenario {
  14. SqlTextView textView;
  15. MenuItem miWrap;
  16. public override void Setup ()
  17. {
  18. Win.Title = this.GetName ();
  19. Win.Y = 1; // menu
  20. Win.Height = Dim.Fill (1); // status bar
  21. Application.Top.LayoutSubviews ();
  22. var menu = new MenuBar (new MenuBarItem [] {
  23. new MenuBarItem ("_File", new MenuItem [] {
  24. miWrap = new MenuItem ("_Word Wrap", "", () => WordWrap()){CheckType = MenuItemCheckStyle.Checked},
  25. new MenuItem ("_Quit", "", () => Quit()),
  26. })
  27. });
  28. Application.Top.Add (menu);
  29. textView = new SqlTextView () {
  30. X = 0,
  31. Y = 0,
  32. Width = Dim.Fill (),
  33. Height = Dim.Fill (1),
  34. };
  35. textView.Init ();
  36. textView.Text = "SELECT TOP 100 * \nfrom\n MyDb.dbo.Biochemistry;";
  37. Win.Add (textView);
  38. var statusBar = new StatusBar (new StatusItem [] {
  39. new StatusItem(Key.CtrlMask | Key.Q, "~^Q~ Quit", () => Quit()),
  40. });
  41. Application.Top.Add (statusBar);
  42. }
  43. private void WordWrap ()
  44. {
  45. miWrap.Checked = !miWrap.Checked;
  46. textView.WordWrap = miWrap.Checked;
  47. }
  48. private void Quit ()
  49. {
  50. Application.RequestStop ();
  51. }
  52. private class SqlTextView : TextView {
  53. private HashSet<string> keywords = new HashSet<string> (StringComparer.CurrentCultureIgnoreCase);
  54. private Attribute blue;
  55. private Attribute white;
  56. private Attribute magenta;
  57. public void Init ()
  58. {
  59. keywords.Add ("select");
  60. keywords.Add ("distinct");
  61. keywords.Add ("top");
  62. keywords.Add ("from");
  63. keywords.Add ("create");
  64. keywords.Add ("CIPHER");
  65. keywords.Add ("CLASS_ORIGIN");
  66. keywords.Add ("CLIENT");
  67. keywords.Add ("CLOSE");
  68. keywords.Add ("COALESCE");
  69. keywords.Add ("CODE");
  70. keywords.Add ("COLUMNS");
  71. keywords.Add ("COLUMN_FORMAT");
  72. keywords.Add ("COLUMN_NAME");
  73. keywords.Add ("COMMENT");
  74. keywords.Add ("COMMIT");
  75. keywords.Add ("COMPACT");
  76. keywords.Add ("COMPLETION");
  77. keywords.Add ("COMPRESSED");
  78. keywords.Add ("COMPRESSION");
  79. keywords.Add ("CONCURRENT");
  80. keywords.Add ("CONNECT");
  81. keywords.Add ("CONNECTION");
  82. keywords.Add ("CONSISTENT");
  83. keywords.Add ("CONSTRAINT_CATALOG");
  84. keywords.Add ("CONSTRAINT_SCHEMA");
  85. keywords.Add ("CONSTRAINT_NAME");
  86. keywords.Add ("CONTAINS");
  87. keywords.Add ("CONTEXT");
  88. keywords.Add ("CONTRIBUTORS");
  89. keywords.Add ("COPY");
  90. keywords.Add ("CPU");
  91. keywords.Add ("CURSOR_NAME");
  92. keywords.Add ("primary");
  93. keywords.Add ("key");
  94. keywords.Add ("insert");
  95. keywords.Add ("alter");
  96. keywords.Add ("add");
  97. keywords.Add ("update");
  98. keywords.Add ("set");
  99. keywords.Add ("delete");
  100. keywords.Add ("truncate");
  101. keywords.Add ("as");
  102. keywords.Add ("order");
  103. keywords.Add ("by");
  104. keywords.Add ("asc");
  105. keywords.Add ("desc");
  106. keywords.Add ("between");
  107. keywords.Add ("where");
  108. keywords.Add ("and");
  109. keywords.Add ("or");
  110. keywords.Add ("not");
  111. keywords.Add ("limit");
  112. keywords.Add ("null");
  113. keywords.Add ("is");
  114. keywords.Add ("drop");
  115. keywords.Add ("database");
  116. keywords.Add ("table");
  117. keywords.Add ("having");
  118. keywords.Add ("in");
  119. keywords.Add ("join");
  120. keywords.Add ("on");
  121. keywords.Add ("union");
  122. keywords.Add ("exists");
  123. Autocomplete.AllSuggestions = keywords.ToList ();
  124. magenta = Driver.MakeAttribute (Color.Magenta, Color.Black);
  125. blue = Driver.MakeAttribute (Color.Cyan, Color.Black);
  126. white = Driver.MakeAttribute (Color.White, Color.Black);
  127. }
  128. protected override void SetNormalColor ()
  129. {
  130. Driver.SetAttribute (white);
  131. }
  132. protected override void SetNormalColor (List<System.Rune> line, int idx)
  133. {
  134. if (IsInStringLiteral (line, idx)) {
  135. Driver.SetAttribute (magenta);
  136. } else
  137. if (IsKeyword (line, idx)) {
  138. Driver.SetAttribute (blue);
  139. } else {
  140. Driver.SetAttribute (white);
  141. }
  142. }
  143. private bool IsInStringLiteral (List<System.Rune> line, int idx)
  144. {
  145. string strLine = new string (line.Select (r => (char)r).ToArray ());
  146. foreach (Match m in Regex.Matches (strLine, "'[^']*'")) {
  147. if (idx >= m.Index && idx < m.Index + m.Length) {
  148. return true;
  149. }
  150. }
  151. return false;
  152. }
  153. private bool IsKeyword (List<System.Rune> line, int idx)
  154. {
  155. var word = IdxToWord (line, idx);
  156. if (string.IsNullOrWhiteSpace (word)) {
  157. return false;
  158. }
  159. return keywords.Contains (word, StringComparer.CurrentCultureIgnoreCase);
  160. }
  161. private string IdxToWord (List<System.Rune> line, int idx)
  162. {
  163. var words = Regex.Split (
  164. new string (line.Select (r => (char)r).ToArray ()),
  165. "\\b");
  166. int count = 0;
  167. string current = null;
  168. foreach (var word in words) {
  169. current = word;
  170. count += word.Length;
  171. if (count > idx) {
  172. break;
  173. }
  174. }
  175. return current?.Trim ();
  176. }
  177. }
  178. }
  179. }