2016-11-14 5 views
2

나는 효율적으로 다음과 같은 방법을 구현하기 위해 찾고 있어요 :Roslyn : 단일 소스 행에 정확한 토큰 + 트리 비아 스팬을 열거 하시겠습니까?

IEnumerable<ColoredSpan> GetSyntaxHighlightedSpansOnLine(int lineNumber); 

나는 Document, SourceText, SyntaxTree 등이있다. ColoredSpan은 일부 색상 및 문자열 (또는 char 초의 다른 소스)의 튜플이라고 가정합니다. 예를 들어,이 코드의 세 번째 줄의 경우 :

namespace Foo 
{ /* Badly formatted coment... 
    which continues here... */ class Bar : public IBaz // TODO: rename classes 
    { 
     ... 

나는 텍스트로 열거 결과를 제공하기 위해 찾고 있어요 :

" ", "which continues here... */", " ", "class", " ", "Bar", " ", 
":", " ", "public", " ", "IBaz", " ", "// TODO: rename classes", "\r\n" 

참고 공백 및 주석 퀴즈를 포함하고, 부분적인 여러 줄의 코멘트를.

Another answer은 AST의 전체 부분을 걷는 CSharpSyntaxWalker를 파생시키는 방법을 가리 킵니다. 그러나 효과적으로 단일 행의 노드로 탐색을 제한하지는 않습니다. 한 줄 단위로 이것은 효율적이지 못하며 어떤 하위 섹션을 쉽게 만들 수 없었습니다. Roslyn "퀴즈"(예 : 여러 줄 주석)가 반환됩니다. 또한 중첩 노드 (예 : 네임 스페이스)를 반환합니다. 내가 code as in this answer 시도

, 라 :

var lineSpan = sf.GetText().Lines[lineNumber].Span; 
var nodes = syntaxTree.GetRoot() 
         .DescendantNodes() 
         .Where(x => x.Span.IntersectsWith(lineSpan)) 

하지만이 다시 비효율적이며, 또한 노드를 (예 : 네임 스페이스)을 중복 반환하고 처리하지 않습니다 전체 AST 하위 트리, 전순 주사를 반환 하찮은 일. 다른 샘플은 전체 문서/스크립트와 함께 작동합니다. 또한 0 옆에있는 API 설명서를 참조했습니다.

코드 분석 API가 효율적으로 이것을 허용합니까? 또는이 방법을 구현하기 위해 사전에 전체 AST를 통과해야하며 내 몸으로 평행 메모리를 소비하는 주관적으로 부피가 큰 데이터 구조를 저장할 필요가 있습니까? this answer?

답변

3

AST에서이 데이터를 재구성 할 수 있지만 더 좋은 API는 Microsoft.CodeAnalysis.Classification.Classifier 형태로 표시됩니다. 그러나 그것은 looks expensive는 동기식 결과를

당신은 당신이 자신의 GetSemanticModel() 메소드를 호출하여 Document 또는 Compilation에서 가져올 수 있습니다 당신이 강조하는 소스 코드의 로슬린 SemanticModel이 필요합니다. 문서를 가져 오는 즉시 곧 SyntaxTreeSourceText을 가져 오는 동시에 가져 오기 및 캐시 할 수 있습니다. Workspace도 필요합니다. 이 경우, Classifier.GetClassifiedSpans()으로 요청할 수 있습니다.

현재 SemanticModel을 쉽게 얻을 수 없다면 Classifier.GetClassifiedSpansAsync()으로 전화하여 특정 TextSpan의 모형을 만들 수 있습니다.

두 가지 변종은 당신이 요구할 수있는 거의 모든 열거 형을 제공합니다.

먼저, 각 열에 대해 약한 형식의 분류 (클래스 이름, 키워드, 연산자 등)를 "enum"문자열 형식으로 반환합니다. 이것들은 ClassificationTypeNames 클래스의 const 멤버와 일치하는 것으로 보이므로 신뢰할 수있는 것 같습니다. ClassificationTypeNames.ClassName 외에도 색상을 쉽게 매핑 할 수 있습니다.단지 분류이 호출이 반환에 걸쳐 있기 때문에

두 번째로, 예를 들어 대한 분류 스팬, 공백은 취소가 누락됩니다. 이 코드는 (귀하의 질문에로) ColoredSpan의 존재를 가정

IEnumerable<ColoredSpan> DescribeLine(int lineNumber) 
{ 
    var lineSpan = sourceText.Lines[lineNumber].Span; 
    var classified = Classifier.GetClassifiedSpans(semanticModel, lineSpan, workspace); 
    var cursor = lineSpan.Start; 

    // Presuming you need a string rather than a TextSpan. 
    Func<TextSpan, string> textOf = x => sourceText.ToString(x); 

    if (!classified.Any()) 
     yield return new ColoredSpan(defaultStyle, textOf(lineSpan)); 

    foreach (var overlap in classified) 
    { 
     var classified = overlap.TextSpan.Intersection(lineSpan).Value; 

     if (classified.Start > cursor) 
     { 
      var unclassified = new TextSpan(cursor, classified.Start - cursor); 
      cursor = classified.Start; 
      yield return new ColoredSpan(defaultStyle, textOf(unclassified)); 
     } 

     var style = StyleFromClassificationType(overlapping.ClassificationType); 

     yield return new ColoredSpan(style, textOf((TextSpan)classified)); 

     cursor = classified.Start + classified.Length; 
    } 

    if (cursor < lineSpan.Start + lineSpan.Length) 
    { 
     var trailing = new TextSpan(cursor, lineSpan.Start + lineSpan.Length - cursor); 
     yield return new ColoredSpan(defaultStyle, textOf(trailing)); 
    } 
} 

과 색상에 ClassificationTypeNames를 매핑하는 StyleFromClassificationType() 도우미 : 당신은 지루한 경우 간단 같은 퀴즈를 포함 스팬의 전체 세트를 재구성해야합니다.

Roslyn은 현재 API에 대한 저자의 의도를 전달할 수있는 API 설명서가 없으므로 vim 및 vigor와 함께이 구현을 사용하기 전에 성능 측정을 권장합니다.

프로파일이 과도하게 비싼했다 경우,이 형식으로 N 가장 최근에 본 소스 라인 표현을 캐시 비교적 사소한 것, 필요한 경우/IF 경우 소스 코드 변경이 캐시를 무효화, 재 계산.

+1

여기에 추가해야 할 문서가 정확히 무엇인지 확실하지 않습니다.이 코드는 Visual Studio에서 사용하는 코드와 동일하지만 여기에 캐싱이 있습니다. 캐싱 질문은 까다 롭습니다. 솔직히 시나리오를 알지 못하면 대답하기가 어렵습니다. –

+0

@JasonMalinowski 감사합니다. 적어도 여기 오른쪽 라인에 있습니다. 끝내주는 Roslyn 코드를 볼 수는 있지만 주석이 거의 없으므로 API 계약을 구현에서 추론하기가 어렵습니다. 따라서 API를 잘못 사용하거나 잘못된 트리를 짖는 것보다는 의도 된대로 API를 코딩하는 것이 어렵습니다. 미래의 자신을 위해 성 가실 성능 문제를 만듭니다. 덧붙여 Roslyn overview wiki에서 구문 강조와 분류 자에 대한 언급을 보는 것이 좋을 것입니다. 그러나 나는 기 스텁에 대해 그렇게 인상해야한다. –