27 февраля 2014 г.

C# реализация подсветки синтаксиса CSS-кода (CSS code syntax highlight)

Очередная задачка вставшая передо мной, это сделать простой редактор CSS-кода с подсветкой синтаксиса. Благо в C# есть замечательный редактор с подсветкой синтаксиса многих основных языков разметки и программирования, и называется он FastColoredTextBox.
Все бы хорошо, но встроенной подсветки CSS там нет! Его можно добавить самому, о чем я и напишу.



Для начала делаем возможным использование стилей самого FastColoredTextBox:
using FastColoredTextBoxNS;
Теперь определим стили которые будем использовать для подсветки CSS-кода:
Style BlueBoldStyle = new TextStyle(Brushes.Blue, null, FontStyle.Bold);
Style MagentaStyle = new TextStyle(Brushes.Magenta, null, FontStyle.Regular);
Style GreenStyle = new TextStyle(Brushes.Green, null, FontStyle.Italic);
Style BrownStyle = new TextStyle(Brushes.Brown, null, FontStyle.Italic);
Style FireBrickBold = new TextStyle(Brushes.Firebrick, null, FontStyle.Bold);
Style DodgerBlue = new TextStyle(Brushes.DodgerBlue, null, FontStyle.Regular);
Style SteelBlue = new TextStyle(Brushes.SteelBlue, null, FontStyle.Regular);
Style DarkGoldenRodBold = new TextStyle(Brushes.DarkGoldenrod , null, FontStyle.Bold);
Style SlateGray  = new TextStyle(Brushes.SlateGray , null, FontStyle.Regular);
Style DarkViolet = new TextStyle(Brushes.DarkViolet , null, FontStyle.Regular);
Цвета поменяйте как душе угодно, по аналогии. Ну и далее нам нужно в событии FastColoredTextBox.TextChanged, "красить" текст, используя регулярные выражения:
void FastColoredTextBoxTextChanged(object sender, FastColoredTextBoxNS.TextChangedEventArgs e) {
 //очищаем стили
 e.ChangedRange.ClearStyle(SlateGray, DarkViolet, DodgerBlue, FireBrickBold, BlueBoldStyle, DarkGoldenRodBold, MagentaStyle, GreenStyle, BrownStyle);
 e.ChangedRange.tb.CommentPrefix = null;
 e.ChangedRange.tb.LeftBracket = '(';
 e.ChangedRange.tb.RightBracket = ')';
 e.ChangedRange.tb.LeftBracket2 = '\x0';
 e.ChangedRange.tb.RightBracket2 = '\x0';
 //строчные переменные "", ''
 e.ChangedRange.SetStyle(BrownStyle, @""".*?""|'.+?'", RegexOptions.Multiline);
 //комментарии
 e.ChangedRange.SetStyle(GreenStyle, @"(/\*.*?\*/)|(/\*.*)", RegexOptions.Multiline);
 e.ChangedRange.SetStyle(GreenStyle, @"(/\*.*?\*/)|(.*\*/)", RegexOptions.Singleline | RegexOptions.RightToLeft); 
 //цифровые поля и цвета #RGB
 e.ChangedRange.SetStyle(MagentaStyle, @"\b(\d+\s*(px|em|pt|in|cm|mm|ex|pc)*)\b(%)*", RegexOptions.Multiline);
 e.ChangedRange.SetStyle(MagentaStyle, @"#\b([a-fA-F0-9]{3,8})\b", RegexOptions.Multiline);
 //ключевые слова
 e.ChangedRange.SetStyle(SteelBlue, @"(-(moz|o|ms|webkit|khtml)-(\w|-)+)", RegexOptions.Multiline);
 e.ChangedRange.SetStyle(FireBrickBold, @"(#:(\w|\.|-)+:#)", RegexOptions.Multiline);
 e.ChangedRange.SetStyle(DodgerBlue, @"\b(font-weight|border-radius|color-stop|alignment-adjust|alignment-baseline|animation|animation-delay|animation-direction|animation-duration|animation-iteration-count|animation-name|animation-play-state|animation-timing-function|appearance|azimuth|backface-visibility|background|background-attachment|background-break|background-clip|background-color|background-image|background-origin|background-position|background-repeat|background-size|baseline-shift|binding|bleed|bookmark-label|bookmark-level|bookmark-state|bookmark-target|border|border|border-bottom|border-bottom-color|border-bottom-left-radius|border-bottom-right-radius|border-bottom-style|border-bottom-width|border-collapse|border-color|border-image|border-image-outset|border-image-repeat|border-image-slice|border-image-source|border-image-width|border-left|border-left-color|border-left-style|border-left-width|border-right|border-right-color|border-right-style|border-right-width|border-spacing|border-style|border-top|border-top-color|border-top-left-radius|border-top-right-radius|border-top-style|border-top-width|border-width|bottom|box-align|box-decoration-break|box-direction|box-flex|box-flex-group|box-lines|box-ordinal-group|box-orient|box-pack|box-shadow|box-sizing|break-after|break-before|break-inside|caption-side|clear|clip|color|color-profile|column-count|column-fill|column-gap|column-rule|column-rule-color|column-rule-style|column-rule-width|column-span|column-width|columns|content|counter-increment|counter-reset|crop|cue|cue-after|cue-before|cursor|direction|display|dominant-baseline|drop-initial-after-adjust|drop-initial-after-align|drop-initial-before-adjust|drop-initial-before-align|drop-initial-size|drop-initial-value|elevation|empty-cells|filter|fit|fit-position|float|float-offset|font|font-effect|font-emphasize|font-family|font-size|font-size-adjust|font-stretch|font-style|font-variant|grid-columns|grid-rows|hanging-punctuation|height|hyphenate-after|hyphenate-before|hyphenate-character|hyphenate-lines|hyphenate-resource|hyphens|icon|image-orientation|image-rendering|image-resolution|inline-box-align|left|letter-spacing|line-height|line-stacking|line-stacking-ruby|line-stacking-shift|line-stacking-strategy|list-style|list-style-image|list-style-position|list-style-type|margin|margin-bottom|margin-left|margin-right|margin-top|mark|mark-after|mark-before|marker-offset|marks|marquee-direction|marquee-play-count|marquee-speed|marquee-style|max-height|max-width|min-height|min-width|move-to|nav-down|nav-index|nav-left|nav-right|nav-up|opacity|orphans|outline|outline-color|outline-offset|outline-style|outline-width|overflow|overflow-style|overflow-x|overflow-y|padding|padding-bottom|padding-left|padding-right|padding-top|page|page-break-after|page-break-before|page-break-inside|page-policy|pause|pause-after|pause-before|perspective|perspective-origin|phonemes|pitch|pitch-range|play-during|position|presentation-level|punctuation-trim|quotes|rendering-intent|resize|rest|rest-after|rest-before|richness|right|rotation|rotation-point|ruby-align|ruby-overhang|ruby-position|ruby-span|size|speak|speak-header|speak-numeral|speak-punctuation|speech-rate|stress|string-set|table-layout|target|target-name|target-new|target-position|text-align|text-align-last|text-decoration|text-emphasis|text-height|text-indent|text-justify|text-outline|text-overflow|text-shadow|text-transform|text-wrap|top|transform|transform-origin|transform-style|transition|transition-delay|transition-duration|transition-property|transition-timing-function|unicode-bidi|vertical-align|visibility|voice-balance|voice-duration|voice-family|voice-pitch|voice-pitch-range|voice-rate|voice-stress|voice-volume|volume|white-space|white-space-collapse|widows|width|word-break|word-spacing|word-wrap|z-index)\b", RegexOptions.Multiline);
 //{ и }
 e.ChangedRange.SetStyle(BlueBoldStyle, @"[\}|\{]", RegexOptions.Multiline);  
 //переменные css
 e.ChangedRange.SetStyle(DarkGoldenRodBold, @"(\}.*?\{)|(\}.*)", RegexOptions.Multiline);
 e.ChangedRange.SetStyle(DarkGoldenRodBold, @"(\}.*?\{)|(.*\{)", RegexOptions.Singleline | RegexOptions.RightToLeft); 
 //знаки пунктуации
 e.ChangedRange.SetStyle(SlateGray, @"[\.|\,|\;|\:|\=|\(|\)|\!]", RegexOptions.Multiline);
 //фильтры Microsoft
 e.ChangedRange.SetStyle(DarkViolet, @"progid\:DXImageTransform\.Microsoft", RegexOptions.Multiline);
 //очищаем маркеры складывания блоков
 e.ChangedRange.ClearFoldingMarkers();
 //устанавливаем новые
 e.ChangedRange.SetFoldingMarkers("{", "}");
 e.ChangedRange.SetFoldingMarkers(@"/\*", @"\*/");
}
Пользуйтесь, правьте как вам нужно. В интернете не нашел такого, поэтому написал тут. Стандартам возможно не соответствует, мне этого оказалось достаточно.

Комментариев нет: