11import * as vscode from 'vscode' ;
22import { DevProxyInstall } from './types' ;
3+ import parse from 'json-to-ast' ;
4+ import { getASTNode , getRangeFromASTNode } from './helpers' ;
35
46export const registerCodeActions = ( context : vscode . ExtensionContext ) => {
57 const devProxyInstall =
@@ -15,6 +17,7 @@ export const registerCodeActions = (context: vscode.ExtensionContext) => {
1517
1618 registerInvalidSchemaFixes ( devProxyVersion , context ) ;
1719 registerDeprecatedPluginPathFixes ( context ) ;
20+ registerLanguageModelFixes ( context ) ;
1821} ;
1922
2023function registerInvalidSchemaFixes (
@@ -130,3 +133,126 @@ function registerDeprecatedPluginPathFixes(context: vscode.ExtensionContext) {
130133 ) ,
131134 ) ;
132135}
136+
137+ function registerLanguageModelFixes ( context : vscode . ExtensionContext ) {
138+ const languageModelMissing : vscode . CodeActionProvider = {
139+ provideCodeActions : ( document , range , context , token ) => {
140+ // Check if the current range intersects with a missing language model diagnostic
141+ const currentDiagnostic = context . diagnostics . find ( diagnostic => {
142+ return (
143+ diagnostic . code === 'missingLanguageModel' &&
144+ diagnostic . range . intersection ( range )
145+ ) ;
146+ } ) ;
147+
148+ // Only provide language model actions if user is on a missing language model diagnostic
149+ if ( ! currentDiagnostic ) {
150+ return [ ] ;
151+ }
152+
153+ const fixes : vscode . CodeAction [ ] = [ ] ;
154+
155+ // Fix to add languageModel configuration
156+ const addLanguageModelFix = new vscode . CodeAction (
157+ 'Add languageModel configuration' ,
158+ vscode . CodeActionKind . QuickFix ,
159+ ) ;
160+
161+ addLanguageModelFix . edit = new vscode . WorkspaceEdit ( ) ;
162+
163+ try {
164+ // Parse the document using json-to-ast for accurate insertion
165+ const documentNode = parse ( document . getText ( ) ) as parse . ObjectNode ;
166+
167+ // Check if languageModel already exists
168+ const existingLanguageModel = getASTNode (
169+ documentNode . children ,
170+ 'Identifier' ,
171+ 'languageModel'
172+ ) ;
173+
174+ if ( existingLanguageModel ) {
175+ // languageModel exists but enabled might be false or missing
176+ const languageModelObjectNode = existingLanguageModel . value as parse . ObjectNode ;
177+ const enabledNode = getASTNode (
178+ languageModelObjectNode . children ,
179+ 'Identifier' ,
180+ 'enabled'
181+ ) ;
182+
183+ if ( enabledNode ) {
184+ // Replace the enabled value
185+ addLanguageModelFix . edit . replace (
186+ document . uri ,
187+ getRangeFromASTNode ( enabledNode . value ) ,
188+ 'true'
189+ ) ;
190+ } else {
191+ // Add enabled property
192+ const insertPosition = new vscode . Position (
193+ languageModelObjectNode . loc ! . end . line - 1 ,
194+ languageModelObjectNode . loc ! . end . column - 1
195+ ) ;
196+ addLanguageModelFix . edit . insert (
197+ document . uri ,
198+ insertPosition ,
199+ '\n "enabled": true'
200+ ) ;
201+ }
202+ } else {
203+ // Add new languageModel object
204+ // Find the last property to insert after it
205+ const lastProperty = documentNode . children [ documentNode . children . length - 1 ] as parse . PropertyNode ;
206+ const insertPosition = new vscode . Position (
207+ lastProperty . loc ! . end . line - 1 ,
208+ lastProperty . loc ! . end . column
209+ ) ;
210+
211+ addLanguageModelFix . edit . insert (
212+ document . uri ,
213+ insertPosition ,
214+ ',\n "languageModel": {\n "enabled": true\n }'
215+ ) ;
216+ }
217+ } catch ( error ) {
218+ // Fallback to simple text-based insertion
219+ const documentText = document . getText ( ) ;
220+ const lines = documentText . split ( '\n' ) ;
221+
222+ // Find where to insert the languageModel config
223+ let insertLine = lines . length - 1 ;
224+ for ( let i = lines . length - 1 ; i >= 0 ; i -- ) {
225+ if ( lines [ i ] . includes ( '}' ) ) {
226+ insertLine = i ;
227+ break ;
228+ }
229+ }
230+
231+ const hasContentBefore = lines . slice ( 0 , insertLine ) . some ( line =>
232+ line . trim ( ) && ! line . trim ( ) . startsWith ( '{' ) && ! line . trim ( ) . startsWith ( '/*' ) && ! line . trim ( ) . startsWith ( '*' )
233+ ) ;
234+
235+ const languageModelConfig = hasContentBefore ?
236+ ',\n "languageModel": {\n "enabled": true\n }' :
237+ ' "languageModel": {\n "enabled": true\n }' ;
238+
239+ const insertPosition = new vscode . Position ( insertLine , 0 ) ;
240+ addLanguageModelFix . edit . insert ( document . uri , insertPosition , languageModelConfig + '\n' ) ;
241+ }
242+
243+ addLanguageModelFix . isPreferred = true ;
244+ fixes . push ( addLanguageModelFix ) ;
245+
246+ return fixes ;
247+ } ,
248+ } ;
249+
250+ // Code action for missing language model configuration
251+ context . subscriptions . push (
252+ vscode . languages . registerCodeActionsProvider ( 'json' , languageModelMissing ) ,
253+ ) ;
254+
255+ context . subscriptions . push (
256+ vscode . languages . registerCodeActionsProvider ( 'jsonc' , languageModelMissing ) ,
257+ ) ;
258+ }
0 commit comments