public void GetSemanticTokens_Razor_SomeTagHelpers_ThenNone() { var txt = $"@addTagHelper *, TestAssembly{Environment.NewLine}<test1></test1>"; var expectedData = new int[] { 1, 1, 5, 0, 0, 0, 8, 5, 0, 0, }; var previousResultId = AssertSemanticTokens(txt, expectedData, isRazor: false, out var service); var newTxt = $"addTagHelper *, TestAssembly{Environment.NewLine}<p></p>"; var newExpectedData = new SemanticTokensDelta { Edits = new List <SemanticTokensEdit> { new SemanticTokensEdit { Start = 0, Data = Array.Empty <int>().ToImmutableArray(), DeleteCount = 10, } } }; var newResultId = AssertSemanticTokenEdits(newTxt, newExpectedData, isRazor: false, previousResultId: previousResultId, out var _, service); Assert.NotEqual(previousResultId, newResultId); }
public void GetSemanticTokens_Razor_OnlyDifferences_NewLines() { var txt = $"@addTagHelper *, TestAssembly{Environment.NewLine}<test1></test1>"; var expectedData = new List <int> { 1, 1, 5, 0, 0, //line, character pos, length, tokenType, modifier 0, 8, 5, 0, 0 }; var previousResultId = AssertSemanticTokens(txt, expectedData, isRazor: false, out var service); var newTxt = $"@addTagHelper *, TestAssembly{Environment.NewLine}<test1></test1>{Environment.NewLine}" + $"<test1></test1>"; var newExpectedData = new SemanticTokensDelta { Edits = new List <SemanticTokensEdit> { new SemanticTokensEdit { Start = 10, Data = new int[] { 1, 1, 5, 0, 0, 0, 8, 5, 0, 0, }.ToImmutableArray(), DeleteCount = 0, } } }; var newResultId = AssertSemanticTokenEdits(newTxt, newExpectedData, isRazor: false, previousResultId: previousResultId, out _, service); Assert.NotEqual(previousResultId, newResultId); }
public async Task <SumType <LSP.SemanticTokens, LSP.SemanticTokensDelta> > HandleRequestAsync( LSP.SemanticTokensDeltaParams request, RequestContext context, CancellationToken cancellationToken) { Contract.ThrowIfNull(request.TextDocument, "TextDocument is null."); Contract.ThrowIfNull(request.PreviousResultId, "previousResultId is null."); Contract.ThrowIfNull(context.Document, "Document is null."); // Even though we want to ultimately pass edits back to LSP, we still need to compute all semantic tokens, // both for caching purposes and in order to have a baseline comparison when computing the edits. var newSemanticTokensData = await SemanticTokensHelpers.ComputeSemanticTokensDataAsync( context.Document, SemanticTokensCache.TokenTypeToIndex, range : null, cancellationToken).ConfigureAwait(false); Contract.ThrowIfNull(newSemanticTokensData, "newSemanticTokensData is null."); // Getting the cached tokens for the document. If we don't have an applicable cached token set, // we can't calculate edits, so we must return all semantic tokens instead. var oldSemanticTokensData = await _tokensCache.GetCachedTokensDataAsync( request.TextDocument.Uri, request.PreviousResultId, cancellationToken).ConfigureAwait(false); if (oldSemanticTokensData == null) { var newResultId = _tokensCache.GetNextResultId(); return(new LSP.SemanticTokens { ResultId = newResultId, Data = newSemanticTokensData }); } var resultId = request.PreviousResultId; var editArray = ComputeSemanticTokensEdits(oldSemanticTokensData, newSemanticTokensData); // If we have edits, generate a new ResultId. Otherwise, re-use the previous one. if (editArray.Length != 0) { resultId = _tokensCache.GetNextResultId(); var updatedTokens = new LSP.SemanticTokens { ResultId = resultId, Data = newSemanticTokensData }; await _tokensCache.UpdateCacheAsync( request.TextDocument.Uri, updatedTokens, cancellationToken).ConfigureAwait(false); } var edits = new SemanticTokensDelta { Edits = editArray, ResultId = resultId }; return(edits); }
public static SemanticTokensFullOrDelta ComputeSemanticTokensEdits( SemanticTokensResponse newTokens, IReadOnlyList <int> previousResults) { var differ = new SemanticTokensEditsDiffer(previousResults, newTokens.Data); var diffs = differ.ComputeDiff(); var edits = differ.ProcessEdits(diffs); var result = new SemanticTokensDelta { ResultId = newTokens.ResultId, Edits = edits, }; return(result); }
public void GetSemanticTokens_Razor_CoalesceDeleteAndAdd() { var txt = $"@addTagHelper *, TestAssembly{Environment.NewLine}<test1 />"; var expectedData = new List <int> { 1, 1, 5, 0, 0, //line, character pos, length, tokenType, modifier }; var previousResultId = AssertSemanticTokens(txt, expectedData, isRazor: false, out var service); var newTxt = $"@addTagHelper *, TestAssembly{Environment.NewLine}{Environment.NewLine} <p @minimized></p>"; var newExpectedData = new SemanticTokensDelta { Edits = new SemanticTokensEdit[] { new SemanticTokensEdit { Start = 0, DeleteCount = 0, Data = new List <int> { 2, 5, }.ToImmutableArray(), }, new SemanticTokensEdit { Start = 1, DeleteCount = 0, Data = new List <int> { 2, 0, 0, }.ToImmutableArray(), }, new SemanticTokensEdit { Start = 2, DeleteCount = 2, Data = new List <int> { 9, 4, }.ToImmutableArray() } } }; var newResultId = AssertSemanticTokenEdits(newTxt, newExpectedData, isRazor: true, previousResultId: previousResultId, out var _, service); Assert.NotEqual(previousResultId, newResultId); }
public void GetSemanticTokens_Razor_Modify() { var txt = $"@addTagHelper *, TestAssembly{Environment.NewLine}" + $"<test1 bool-val=\"true\" />{Environment.NewLine}" + $"<test1 bool-val=\"true\" />{Environment.NewLine}" + $"<test1 bool-val=\"true\" />{Environment.NewLine}"; var expectedData = new List <int> { 1, 1, 5, 0, 0, //line, character pos, length, tokenType, modifier 0, 6, 8, 1, 0, 1, 1, 5, 0, 0, 0, 6, 8, 1, 0, 1, 1, 5, 0, 0, 0, 6, 8, 1, 0, }; var previousResultId = AssertSemanticTokens(txt, expectedData, isRazor: false, out var service); var newTxt = $"@addTagHelper *, TestAssembly{Environment.NewLine}" + $"<test1 bool-va=\"true\" />{Environment.NewLine}" + $"<test1 bool-val=\"true\" />{Environment.NewLine}" + $"<test1 bool-val=\"true\" />{Environment.NewLine}"; var newExpectedData = new SemanticTokensDelta { Edits = new List <SemanticTokensEdit> { new SemanticTokensEdit { Start = 5, Data = Array.Empty <int>().ToImmutableArray(), DeleteCount = 5, }, } }; var newResultId = AssertSemanticTokenEdits(newTxt, newExpectedData, isRazor: false, previousResultId: previousResultId, out _, service); Assert.NotEqual(previousResultId, newResultId); }
public SemanticTokensFullOrDelta GetSemanticTokensEdits() { if (!_prevData.HasValue) { return(GetSemanticTokens()); } var prevData = _prevData.Value; var prevDataLength = prevData.Length; var dataLength = Data.Length; var startIndex = 0; while (startIndex < dataLength && startIndex < prevDataLength && prevData[startIndex] == Data[startIndex]) { startIndex++; } if (startIndex < dataLength && startIndex < prevDataLength) { // Find end index var endIndex = 0; while (endIndex < dataLength && endIndex < prevDataLength && prevData[prevDataLength - 1 - endIndex] == Data[dataLength - 1 - endIndex]) { endIndex++; } var newData = ImmutableArray.Create(Data, startIndex, dataLength - endIndex - startIndex); var result = new SemanticTokensDelta { ResultId = Id, Edits = new[] { new SemanticTokensEdit { Start = startIndex, DeleteCount = prevDataLength - endIndex - startIndex, Data = newData } } }; return(result); } if (startIndex < dataLength) { return(new SemanticTokensDelta { ResultId = Id, Edits = new[] { new SemanticTokensEdit { Start = startIndex, DeleteCount = 0, Data = ImmutableArray.Create(Data, startIndex, DataLen - startIndex) } } }); } if (startIndex < prevDataLength) { return(new SemanticTokensDelta { ResultId = Id, Edits = new[] { new SemanticTokensEdit { Start = startIndex, DeleteCount = prevDataLength - startIndex } } }); } return(new SemanticTokensDelta { ResultId = Id, Edits = Array.Empty <SemanticTokensEdit>() }); }