Roslyn – очень классная штука, с помощью которой можно не только анализаторы делать, но и много других интересных штук.
Вот, например, сколько потребуется усилий, чтобы сделать раскрашиватель синтаксиса, который будет печатать C#-файл в консоль и подсвечивать ключевые слова, строковые литералы и т.п вещи?
Вот как это можно сделать.
Подсветка синтаксиса состоит из нескольких этапов. Вначале нужно прочитать C#-файл и получить синтаксическое дерево. Потом нужно проанализировать дерево и получить «классификацию» символов – являются ли элементы дерева ключевыми словами, идентификаторами, строковыми литералами и т.п. Потом нужно пробежаться по исходному коду и получить цвет символа, в зависимости от классификации, и установить нужный цвет консоли.
1. Получение документа и синтаксического дерева
Существует несколько способов получить синтаксическое дерево из строки. Самый простой способ, вызвать метод CSharpSyntaxTree.ParseText. В этот раз этот подход не сработает, поскольку помимо синтаксического дерева классификатору (классу Classifier) нужно получить еще и Workspace и Document. Поэтому используем другой способ:
private static Document CreateDocumentFrom(string sourceCode)
{
var workspace = new AdhocWorkspace();
Solution solution = workspace.CurrentSolution;
Project project = solution.AddProject("SyntaxHighlighter", "SyntaxHighlighter",
LanguageNames.CSharp);
Document document = project.AddDocument("source.cs", sourceCode);
return document;
}
2. Классифицировать дерево с помощью класса Classifier
Метод Classifier.GetClassifiedSpansAsync возвращает список ClassifiedSpan – список простых объектов значений (value objects) с парой свойств: TextSpan и ClassificationType, которые определяют диапазон в исходном коде и тип символа, такие как StringLiteral, Identifier etc.
public static async Task PrintSourceAsync(string sourceCode)
{
// Получаем документ по исходному коду
Document document = CreateDocumentFrom(sourceCode);
var syntaxTreeRoot = await document.GetSyntaxRootAsync();
// Getting classification for the document
IEnumerable<ClassifiedSpan> classification =
await Classifier.GetClassifiedSpansAsync(document, syntaxTreeRoot.FullSpan);
// Получаем мапу между началом нового символа и цветом
IDictionary<int, ConsoleColor> positionColorMap =
classification.ToDictionary(
c => c.TextSpan.Start, c => GetColorFor(c.ClassificationType));
3. Вывести на консоль содержимое файла
Вывод на консоль достаточно прост. Перебираем все элементы, и если текущий символ относится к новому символу, то изменяем цвет консоли:
Console.BackgroundColor = ConsoleColor.Black;
// Iterating over each character in source file and printing it
for (int charPosition = 0; charPosition < sourceCode.Length; charPosition++)
{
// Проверяем, нужно ли изменять цвет консоли
ConsoleColor newColor;
if (positionColorMap.TryGetValue(charPosition, out newColor))
{
Console.ForegroundColor = newColor;
}
Console.Write(sourceCode[charPosition]);
}
Console.ResetColor();
} // Конец метода PrintSourceAsync
Нужно еще метод, который будет получать цвет в зависимости от классификации символа и вывести текст на консоль. Для получения цвета подойдет простой switch:
private static ConsoleColor GetColorFor(string classificatioName)
{
switch (classificatioName)
{
case ClassificationTypeNames.InterfaceName:
case ClassificationTypeNames.EnumName:
case ClassificationTypeNames.Keyword:
return ConsoleColor.DarkCyan;
case ClassificationTypeNames.ClassName:
case ClassificationTypeNames.StructName:
return ConsoleColor.DarkYellow;
case ClassificationTypeNames.Identifier:
return ConsoleColor.DarkGray;
case ClassificationTypeNames.Comment:
return ConsoleColor.DarkGreen;
case ClassificationTypeNames.StringLiteral:
case ClassificationTypeNames.VerbatimStringLiteral:
return ConsoleColor.DarkRed;
case ClassificationTypeNames.Punctuation:
return ConsoleColor.Gray;
case ClassificationTypeNames.WhiteSpace:
return ConsoleColor.Black;
case ClassificationTypeNames.NumericLiteral:
return ConsoleColor.DarkYellow;
case ClassificationTypeNames.PreprocessorKeyword:
return ConsoleColor.DarkMagenta;
case ClassificationTypeNames.PreprocessorText:
return ConsoleColor.DarkGreen;
default:
return ConsoleColor.Gray;
}
}
Все, метод PrintSourceAsync, и теперь его можно использовать для вывода C# кода на консоль с расцветкой синтаксиса. Вот пример запуска:
Подсветка синтаксиса далека от идеала, да и класс Classifier дает далеко не все типы узлов. Но расширить решение не так и сложно. В любом случае, впечатляет, что в 100 строках кода умещается очень даже толковый syntax highlighter.
З.Ы. Все исходники на гитхабе в репозитории PlayingWithRoslyn.
Круто!
ОтветитьУдалитьProgramming Stuff: Простой Syntax Highlighter На Базе Roslyn >>>>> Download Now
Удалить>>>>> Download Full
Programming Stuff: Простой Syntax Highlighter На Базе Roslyn >>>>> Download LINK
>>>>> Download Now
Programming Stuff: Простой Syntax Highlighter На Базе Roslyn >>>>> Download Full
>>>>> Download LINK so
Круто!
ОтветитьУдалитьСпасибо!
УдалитьКруто :) А не подскажешь случайно подноценный скрипт-едит-контрол на рослине, чтобы была подсветка синтаксиса, автокомплит и поддержка ссылок на сборки (references)? А то много где пишут что с помощью Roslyn такое должно быть достаточно легко реализуемо, но что-то из готового находятся одни поделки... Т.е. ищется что-то типа AvalonEdit (http://avalonedit.net/) из SharpDevelop, но на базе рослина. Не встречалось?
ОтветитьУдалитьПоскольку сейчас в репе розлина стало больше всего, может быть там что-то такое есть. Навскидку - не подскажу:((
УдалитьРекомендую посмотреть в сторону FastColoredTextBox (
Удалитьhttp://www.codeproject.com/Articles/161871/Fast-Colored-TextBox-for-syntax-highlighting). Очень, очень мощный компонент. На гитхабе вместе с исходниками есть и демка, поражающая разнообразием возможностей.
ПС. Пардон за некропостинг )
Правда он не на рослине.
УдалитьПривет, небольшой оффтоп: а что вы используете для подсветки синтаксиса сниппетов кода в блоге (кажется, уже упоминали где-то, но не получается найти)?
ОтветитьУдалитьЯ использую Windows Live Writer (который, кстати, недавно заоупенсорсили) и прото копирую из студии (но для этого в студии должен быть установел Productivity Power Tools и включен Copy AsHTML компонент).
УдалитьКласс, стал постоянным читателем вашего блога. Также купил вашу книгу про патерны проектирования. Вобщем хочу сказать вам спасбо Сергей.
ОтветитьУдалитьКласс, стал постоянным читателем вашего блога. Также купил вашу книгу про патерны проектирования. Вобщем хочу сказать вам спасбо Сергей.
ОтветитьУдалитьАрсений, я рад новым читателям! Спасибо за отзывы!
УдалитьProgramming Stuff: Простой Syntax Highlighter На Базе Roslyn >>>>> Download Now
ОтветитьУдалить>>>>> Download Full
Programming Stuff: Простой Syntax Highlighter На Базе Roslyn >>>>> Download LINK
>>>>> Download Now
Programming Stuff: Простой Syntax Highlighter На Базе Roslyn >>>>> Download Full
>>>>> Download LINK nr