使用NRefactory 5完成C#代码完成

时间:2012-09-20 05:41:19

标签: c# code-completion nrefactory

我刚刚发现NRefactory 5,我猜,它是我当前问题最合适的解决方案。目前我正在开发一个小C#脚本应用程序,我想提供代码完成。直到最近,我才使用微软的“Roslyn”项目完成了这项工作。但是由于该项目的最新更新需要.Net Framework 4.5,我不能再使用它,因为我希望该应用程序也可以在Win XP下运行。所以我必须在这里切换到另一种技术。

我的问题不在于编译。这可以通过.Net CodeDomProvider进行更多努力。问题在于代码完成的东西。据我所知,NRefactory 5提供了提供代码完成所需的一切(解析器,类型系统等),但我无法弄清楚如何使用它。我看了一下SharpDevelop源代码,但他们没有使用NRefactory 5来完成代码,他们只将它用作反编译器。因为我找不到一个关于如何在网络中使用它来完成代码的示例,我认为我可能会在这里找到一些帮助。

情况如下。我有一个包含脚本代码的文件。实际上它甚至不是一个文件,而是一个从编辑器控件中得到的字符串(顺便说一句:我正在使用AvalonEdit。伟大的编辑器!)和一些需要引用的程序集。因此,没有解决方案文件,没有项目文件等,只有一串源代码和程序集。

我看过NRefactory 5附带的Demo和关于代码项目的文章,并得到了类似的东西:

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 个答案:

答案 0 :(得分:6)

我刚编译并使用AvalonEdit和NRefactory完成C#代码完成的示例项目。

可以是found on Github here.

答案 1 :(得分:2)

SharpDevelop 5正在使用NRefactory 5. SharpDevelop 5的源代码目前在newNR branch on github中可用。我将看一下CSharpCompletionBinding class,其中包含使用NRefactory的CSharpCompletionEngine信息显示完成列表窗口的代码。

答案 2 :(得分:2)

查看方法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;

}

}

希望它有所帮助,   马特拉