Завершение кода 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.

Другие вопросы по тегам