Завершение кода C# с NRefactory 5
Я только что узнал о NRefactory 5 и думаю, что это наиболее подходящее решение для моей текущей проблемы. В данный момент я занимаюсь разработкой небольшого скриптового приложения на C#, для которого я хотел бы обеспечить завершение кода. До недавнего времени я делал это с помощью проекта "Roslyn" от Microsoft. Но поскольку для последнего обновления этого проекта требуется.Net Framework 4.5, я больше не могу его использовать, так как мне бы хотелось, чтобы приложение также работало под Win XP. Поэтому я должен перейти на другую технологию здесь.
Моя проблема не в компиляции. Это может быть сделано, с некоторыми дополнительными усилиями, также.Net CodeDomProvider. Проблема заключается в том, что такое завершение кода. Насколько я знаю, NRefactory 5 предоставляет все, что требуется для обеспечения завершения кода (анализатор, система типов и т. Д.), Но я просто не могу понять, как его использовать. Я взглянул на исходный код SharpDevelop, но они не используют NRefactory 5 для завершения кода, они используют его только как декомпилятор. Так как я не смог найти пример того, как использовать его для завершения кода в сети, я подумал, что я мог бы найти некоторую помощь здесь.
Ситуация следующая. У меня есть один файл, содержащий код скрипта. На самом деле это даже не файл, а строка, которую я получаю из элемента управления редактора (кстати: я использую AvalonEdit для этого. Отличный редактор!) И некоторые сборки, на которые нужно ссылаться. Таким образом, нет файлов решения, файлов проекта и т. Д., Только одна строка исходного кода и сборок.
Я взглянул на демонстрацию, которая поставляется с NRefactory 5, и статью о проекте кода и получил что-то вроде этого:
var unresolvedTypeSystem = syntaxTree.ToTypeSystem();
IProjectContent pc = new CSharpProjectContent();
// Add parsed files to the type system
pc = pc.AddOrUpdateFiles(unresolvedTypeSystem);
// Add referenced assemblies:
pc = pc.AddAssemblyReferences(new CecilLoader().LoadAssemblyFile(
System.Reflection.Assembly.GetAssembly(typeof(Object)).Location));
Моя проблема в том, что я понятия не имею, что делать дальше. Я даже не уверен, что это правильный подход для достижения моей цели. Как использовать CSharpCompletionEngine? Что еще требуется? и т.д. Вы видите, что есть много вещей, которые в настоящее время очень неясны, и я надеюсь, что вы сможете пролить свет на это.
Спасибо всем большое заранее!
3 ответа
Взгляните на метод ICSharpCode.NRefactory.CSharp.CodeCompletion.CreateEngine
, Вам нужно создать экземпляр CSharpCompletionEngine
и передайте правильный документ и решатели. Мне удалось заставить его работать для сценария CTRL+Space Compltition. Однако у меня возникают проблемы со ссылками на типы, которые находятся в других пространствах имен. Это выглядит как CSharpTypeResolveContext
не учитывает использование операторов пространства имен - если я разрешу ссылки с CSharpAstResolver
, они решены хорошо, но я не могу правильно использовать этот преобразователь в сценарии завершения кода...
ОБНОВЛЕНИЕ № 1:
Мне только удалось получить работу, получив решатель от неразрешенного сбоя.
Вот фрагмент:
var mb = new DefaultCompletionContextProvider(doc, unresolvedFile);
var resolver3 = unresolvedFile.GetResolver(cmp, loc); // get the resolver from unresolvedFile
var engine = new CSharpCompletionEngine(doc, mb, new CodeCompletionBugTests.TestFactory(resolver3), pctx, resolver3.CurrentTypeResolveContext );
Обновление № 2:
Вот полный метод. Он ссылается на классы из проектов модульных тестов, поэтому вам нужно ссылаться на них / копировать их в ваш проект:
public static IEnumerable<ICompletionData> DoCodeComplete(string editorText, int offset) // not the best way to put in the whole string every time
{
var doc = new ReadOnlyDocument(editorText);
var location = doc.GetLocation(offset);
string parsedText = editorText; // TODO: Why there are different values in test cases?
var syntaxTree = new CSharpParser().Parse(parsedText, "program.cs");
syntaxTree.Freeze();
var unresolvedFile = syntaxTree.ToTypeSystem();
var mb = new DefaultCompletionContextProvider(doc, unresolvedFile);
IProjectContent pctx = new CSharpProjectContent();
var refs = new List<IUnresolvedAssembly> { mscorlib.Value, systemCore.Value, systemAssembly.Value};
pctx = pctx.AddAssemblyReferences(refs);
pctx = pctx.AddOrUpdateFiles(unresolvedFile);
var cmp = pctx.CreateCompilation();
var resolver3 = unresolvedFile.GetResolver(cmp, location);
var engine = new CSharpCompletionEngine(doc, mb, new CodeCompletionBugTests.TestFactory(resolver3), pctx, resolver3.CurrentTypeResolveContext );
engine.EolMarker = Environment.NewLine;
engine.FormattingPolicy = FormattingOptionsFactory.CreateMono();
var data = engine.GetCompletionData(offset, controlSpace: false);
return data;
}
}
Надеюсь, это поможет, Матра
Я только что скомпилировал и пример проекта, который выполняет завершение кода C# с AvalonEdit и NRefactory.
Его можно найти на Github здесь.
NRefactory 5 используется в SharpDevelop 5. Исходный код для SharpDevelop 5 в настоящее время доступен в ветке newNR на github. Я хотел бы взглянуть на класс CSharpCompletionBinding, который имеет код для отображения окна списка завершения, используя информацию из CSharpCompletionEngine NRefactory.