@@ -5,11 +5,13 @@ import { setLastScanFiles } from './scanStore'
55import { RepoLayoutStorage } from './storage'
66import { initValidation , notifyInitialScanComplete } from './validation'
77import { isGtsCandidateFile } from './helpers'
8+ import { GtsLinkProvider } from './linkProvider'
89import type { LayoutSaveRequest , LayoutTarget , LayoutSnapshot } from '@gts/layout-storage'
910
1011let viewerPanel : vscode . WebviewPanel | null = null
1112let layoutStorage : RepoLayoutStorage | null = null
1213let hasPerformedInitialScan : boolean = false // Track if initial scan with default file has been done
14+ let gtsLinkProvider : GtsLinkProvider | null = null
1315
1416function getNonce ( ) : string {
1517 let text = ''
@@ -75,6 +77,15 @@ async function scanAndPost(includeGlob: string = '**/*.{json,jsonc,gts}', isInit
7577 viewerPanel ! . webview . postMessage ( { type : 'gts-scan-result' , detail : { files, defaultFilePath : selectedFilePath } } )
7678 try { setLastScanFiles ( files ) } catch { }
7779
80+ // Refresh the link provider with the latest registry
81+ if ( gtsLinkProvider ) {
82+ try {
83+ await gtsLinkProvider . refresh ( )
84+ } catch ( e ) {
85+ console . error ( '[GTS] Error refreshing link provider:' , e )
86+ }
87+ }
88+
7889 try {
7990 const objs = Array . from ( registry . jsonObjs . values ( ) ) . map ( o => ( { id : o . id , listSequence : o . listSequence , filePath : o . file ?. path , schemaId : o . schemaId , validation : o . validation } ) )
8091 const schemas = Array . from ( registry . jsonSchemas . values ( ) ) . map ( s => ( { id : s . id , filePath : s . file ?. path , validation : s . validation } ) )
@@ -107,13 +118,104 @@ export async function activate(context: vscode.ExtensionContext) {
107118
108119 initValidation ( context )
109120
121+ // Create diagnostic collection for GTS validation
122+ const gtsDiagnostics = vscode . languages . createDiagnosticCollection ( 'gts' )
123+ context . subscriptions . push ( gtsDiagnostics )
124+
125+ // Initialize and register GTS link provider for clickable GTS IDs
126+ gtsLinkProvider = new GtsLinkProvider ( gtsDiagnostics )
127+
128+ // Register link provider for JSON, JSONC, and GTS files
129+ const documentSelector : vscode . DocumentSelector = [
130+ { language : 'json' , scheme : 'file' } ,
131+ { language : 'jsonc' , scheme : 'file' } ,
132+ { language : 'gts' , scheme : 'file' }
133+ ]
134+
135+ context . subscriptions . push (
136+ vscode . languages . registerDocumentLinkProvider ( documentSelector , gtsLinkProvider )
137+ )
138+
139+ context . subscriptions . push (
140+ vscode . languages . registerHoverProvider ( documentSelector , gtsLinkProvider )
141+ )
142+
143+ // Update decorations when active editor changes
144+ context . subscriptions . push (
145+ vscode . window . onDidChangeActiveTextEditor ( editor => {
146+ if ( editor && gtsLinkProvider ) {
147+ gtsLinkProvider . updateDecorations ( editor )
148+ }
149+ } )
150+ )
151+
152+ // Update decorations when document changes
153+ context . subscriptions . push (
154+ vscode . workspace . onDidChangeTextDocument ( event => {
155+ const editor = vscode . window . activeTextEditor
156+ if ( editor && editor . document === event . document && gtsLinkProvider ) {
157+ gtsLinkProvider . updateDecorations ( editor )
158+ }
159+ } )
160+ )
161+
162+ // Initial decoration for all visible editors
163+ if ( gtsLinkProvider ) {
164+ for ( const editor of vscode . window . visibleTextEditors ) {
165+ gtsLinkProvider . updateDecorations ( editor )
166+ }
167+ }
168+
169+ console . log ( '[GTS] Link provider registered for JSON/JSONC/GTS files' )
170+
110171 // Register commands
111172 context . subscriptions . push (
112173 vscode . commands . registerCommand ( 'gts.openViewer' , ( resource ?: vscode . Uri ) => {
113174 openViewer ( context , resource )
114175 } )
115176 )
116177
178+ // Register command to replace erroneous GTS ID with suggestion
179+ context . subscriptions . push (
180+ vscode . commands . registerCommand ( 'gts.replaceGtsId' , async ( documentUri : string , rangeData : any , newText : string , includeQuotes : boolean ) => {
181+ try {
182+ const uri = vscode . Uri . parse ( documentUri )
183+ const document = await vscode . workspace . openTextDocument ( uri )
184+ const editor = await vscode . window . showTextDocument ( document )
185+
186+ // Reconstruct the Range from serialized data
187+ let range = new vscode . Range (
188+ rangeData . start . line ,
189+ rangeData . start . character ,
190+ rangeData . end . line ,
191+ rangeData . end . character
192+ )
193+
194+ // If we need to include quotes, extend the range and wrap the text
195+ let replacementText = newText
196+ if ( includeQuotes ) {
197+ // Extend range to include the quotes (one character before and after)
198+ range = new vscode . Range (
199+ rangeData . start . line ,
200+ rangeData . start . character - 1 ,
201+ rangeData . end . line ,
202+ rangeData . end . character + 1
203+ )
204+ replacementText = `"${ newText } "`
205+ }
206+
207+ await editor . edit ( editBuilder => {
208+ editBuilder . replace ( range , replacementText )
209+ } )
210+
211+ // Show success message
212+ vscode . window . showInformationMessage ( `Replaced with: ${ newText } ` )
213+ } catch ( error ) {
214+ vscode . window . showErrorMessage ( `Failed to replace GTS ID: ${ error } ` )
215+ }
216+ } )
217+ )
218+
117219 // Show welcome message
118220 vscode . window . showInformationMessage ( 'GTS Viewer is ready! Use "GTS: Open Viewer" to start.' )
119221}
@@ -157,6 +259,16 @@ async function performInitialScan() {
157259 await registry . ingestFiles ( files , DEFAULT_GTS_CONFIG )
158260 console . log ( `[GTS] Registry initialized: ${ registry . jsonSchemas . size } schemas, ${ registry . jsonObjs . size } objects` )
159261
262+ // Refresh the link provider with the initial scan data
263+ if ( gtsLinkProvider ) {
264+ try {
265+ await gtsLinkProvider . refresh ( )
266+ console . log ( '[GTS] Link provider refreshed with initial scan data' )
267+ } catch ( e ) {
268+ console . error ( '[GTS] Error refreshing link provider:' , e )
269+ }
270+ }
271+
160272 // Notify validation system that initial scan is complete
161273 notifyInitialScanComplete ( )
162274 } catch ( error ) {
@@ -173,6 +285,11 @@ export async function deactivate() {
173285 viewerPanel = null
174286 }
175287
288+ if ( gtsLinkProvider ) {
289+ gtsLinkProvider . dispose ( )
290+ gtsLinkProvider = null
291+ }
292+
176293 layoutStorage = null
177294}
178295
0 commit comments