@@ -14,10 +14,11 @@ internal sealed class LanguageServicesClient(
1414 BlazorMonacoInterop blazorMonacoInterop )
1515{
1616 private Dictionary < string , string > modelUrlToFileName = [ ] ;
17- private IDisposable ? completionProvider , semanticTokensProvider ;
17+ private IDisposable ? completionProvider , semanticTokensProvider , codeActionProvider ;
1818 private string ? currentModelUrl ;
1919 private DebounceInfo completionDebounce = new ( new CancellationTokenSource ( ) ) ;
2020 private DebounceInfo diagnosticsDebounce = new ( new CancellationTokenSource ( ) ) ;
21+ private ( string ModelUri , string ? RangeJson , Task < string ? > Result ) ? lastCodeActions ;
2122
2223 public bool Enabled => completionProvider != null ;
2324
@@ -87,7 +88,7 @@ private async Task RegisterAsync()
8788 }
8889
8990 var cSharpLanguageSelector = new LanguageSelector ( "csharp" ) ;
90- completionProvider = await blazorMonacoInterop . RegisterCompletionProviderAsync ( cSharpLanguageSelector , new ( loggerFactory . CreateLogger < CompletionItemProviderAsync > ( ) )
91+ completionProvider = await blazorMonacoInterop . RegisterCompletionProviderAsync ( cSharpLanguageSelector , new ( loggerFactory )
9192 {
9293 TriggerCharacters = [ " " , "(" , "=" , "#" , "." , "<" , "[" , "{" , "\" " , "/" , ":" , ">" , "~" ] ,
9394 ProvideCompletionItemsFunc = ( modelUri , position , context , cancellationToken ) =>
@@ -96,29 +97,35 @@ private async Task RegisterAsync()
9697 ref completionDebounce ,
9798 ( worker , modelUri , position , context ) ,
9899 """{"suggestions":[],"isIncomplete":true}""" ,
99- static ( args , cancellationToken ) => args . worker . ProvideCompletionItemsAsync ( args . modelUri , args . position , args . context ) ,
100+ static ( args , cancellationToken ) => args . worker . ProvideCompletionItemsAsync ( args . modelUri , args . position , args . context , cancellationToken ) ,
100101 cancellationToken ) ;
101102 } ,
102- ResolveCompletionItemFunc = ( completionItem , cancellationToken ) => worker . ResolveCompletionItemAsync ( completionItem ) ,
103+ ResolveCompletionItemFunc = worker . ResolveCompletionItemAsync ,
103104 } ) ;
104105
105- semanticTokensProvider = await blazorMonacoInterop . RegisterSemanticTokensProviderAsync ( cSharpLanguageSelector , new SemanticTokensProvider
106+ semanticTokensProvider = await blazorMonacoInterop . RegisterSemanticTokensProviderAsync ( cSharpLanguageSelector , new ( loggerFactory )
106107 {
107108 Legend = new SemanticTokensLegend
108109 {
109110 TokenTypes = SemanticTokensUtil . TokenTypes . LspValues ,
110111 TokenModifiers = SemanticTokensUtil . TokenModifiers . LspValues ,
111112 } ,
112- ProvideSemanticTokens = ( modelUri , rangeJson , debug , cancellationToken ) =>
113+ ProvideSemanticTokens = worker . ProvideSemanticTokensAsync ,
114+ } ) ;
115+
116+ codeActionProvider = await blazorMonacoInterop . RegisterCodeActionProviderAsync ( cSharpLanguageSelector , new ( loggerFactory )
117+ {
118+ ProvideCodeActions = ( modelUri , rangeJson , cancellationToken ) =>
113119 {
114- return DebounceAsync (
115- ref diagnosticsDebounce ,
116- ( worker , modelUri , debug , rangeJson ) ,
117- // Fallback value when cancelled is `null` which causes an exception to be thrown
118- // instead of returning empty tokens which would cause the semantic colorization to disappear.
119- null ,
120- static ( args , cancellationToken ) => args . worker . ProvideSemanticTokensAsync ( args . modelUri , args . rangeJson , args . debug ) ,
121- cancellationToken ) ;
120+ if ( lastCodeActions is { } cached &&
121+ cached . ModelUri == modelUri && cached . RangeJson == rangeJson )
122+ {
123+ return cached . Result ;
124+ }
125+
126+ var result = worker . ProvideCodeActionsAsync ( modelUri , rangeJson , cancellationToken ) ;
127+ lastCodeActions = ( modelUri , rangeJson , result ) ;
128+ return result ;
122129 } ,
123130 } ) ;
124131 }
@@ -129,6 +136,14 @@ private void Unregister()
129136 completionProvider = null ;
130137 semanticTokensProvider ? . Dispose ( ) ;
131138 semanticTokensProvider = null ;
139+ codeActionProvider ? . Dispose ( ) ;
140+ codeActionProvider = null ;
141+ InvalidateCaches ( ) ;
142+ }
143+
144+ private void InvalidateCaches ( )
145+ {
146+ lastCodeActions = null ;
132147 }
133148
134149 public void OnDidChangeWorkspace ( ImmutableArray < ModelInfo > models , bool updateDiagnostics = true )
@@ -138,6 +153,7 @@ public void OnDidChangeWorkspace(ImmutableArray<ModelInfo> models, bool updateDi
138153 return ;
139154 }
140155
156+ InvalidateCaches ( ) ;
141157 modelUrlToFileName = models . ToDictionary ( m => m . Uri , m => m . FileName ) ;
142158 worker . OnDidChangeWorkspace ( models ) ;
143159
@@ -166,6 +182,7 @@ public void OnDidChangeModelContent(ModelContentChangedEvent args)
166182 return ;
167183 }
168184
185+ InvalidateCaches ( ) ;
169186 worker . OnDidChangeModelContent ( args ) ;
170187 UpdateDiagnostics ( ) ;
171188 }
0 commit comments