@@ -170,6 +170,13 @@ function activate(context) {
170170 } )
171171 ) ;
172172
173+ // Register the document symbol provider for outline view and breadcrumbs
174+ context . subscriptions . push (
175+ vscode . languages . registerDocumentSymbolProvider (
176+ { language : 'combine-datacard' } ,
177+ new CombineDocumentSymbolProvider ( )
178+ )
179+ ) ;
173180}
174181
175182function hasShapeSection ( document ) {
@@ -454,6 +461,145 @@ class CombineCompletionItemProvider {
454461 }
455462}
456463
464+ class CombineDocumentSymbolProvider {
465+ provideDocumentSymbols ( document , token ) {
466+ const symbols = [ ] ;
467+ const dashLineRegex = / ^ - { 3 , } $ / ;
468+ const dashLineNumbers = [ ] ;
469+ const hasShape = hasShapeSection ( document ) ;
470+
471+ // Find all section dividers
472+ for ( let i = 0 ; i < document . lineCount ; i ++ ) {
473+ const lineText = document . lineAt ( i ) . text . trim ( ) ;
474+ if ( dashLineRegex . test ( lineText ) ) {
475+ dashLineNumbers . push ( i ) ;
476+ }
477+ }
478+
479+ // Create symbols for each section
480+ if ( dashLineNumbers . length > 0 ) {
481+ // Handle content before first divider as a section
482+ if ( dashLineNumbers [ 0 ] > 0 ) {
483+ const preHeaderRange = new vscode . Range ( 0 , 0 , dashLineNumbers [ 0 ] - 1 , document . lineAt ( dashLineNumbers [ 0 ] - 1 ) . text . length ) ;
484+ let isHeader = false ;
485+
486+ // Check if this section contains the header block (imax/jmax/kmax)
487+ for ( let i = 0 ; i <= Math . min ( dashLineNumbers [ 0 ] - 3 , document . lineCount - 3 ) ; i ++ ) {
488+ if ( document . lineAt ( i ) . text . trim ( ) . startsWith ( 'imax' ) &&
489+ document . lineAt ( i + 1 ) . text . trim ( ) . startsWith ( 'jmax' ) &&
490+ document . lineAt ( i + 2 ) . text . trim ( ) . startsWith ( 'kmax' ) ) {
491+ isHeader = true ;
492+ break ;
493+ }
494+ }
495+
496+ symbols . push ( new vscode . DocumentSymbol (
497+ isHeader ? "Header section" : "Pre-header section" ,
498+ "" ,
499+ vscode . SymbolKind . String ,
500+ preHeaderRange ,
501+ preHeaderRange
502+ ) ) ;
503+ }
504+
505+ // Handle sections between dividers
506+ for ( let i = 0 ; i < dashLineNumbers . length - 1 ; i ++ ) {
507+ const startLine = dashLineNumbers [ i ] + 1 ;
508+ const endLine = dashLineNumbers [ i + 1 ] - 1 ;
509+
510+ if ( endLine >= startLine ) {
511+ const sectionRange = new vscode . Range ( startLine , 0 , endLine , document . lineAt ( endLine ) . text . length ) ;
512+ const sectionInfo = getSectionIndex ( document , startLine ) ;
513+ const adjustedSection = calculateAdjustedSection ( sectionInfo , hasShape ) ;
514+
515+ // Get section name using the same logic as CombineCompletionItemProvider
516+ let sectionName = "Other section" ;
517+ switch ( adjustedSection ) {
518+ case - 1 :
519+ sectionName = "Pre-header section" ;
520+ break ;
521+ case 0 :
522+ sectionName = "Header section" ;
523+ break ;
524+ case 1 :
525+ sectionName = "Shapes section" ;
526+ break ;
527+ case 2 :
528+ sectionName = "Channel definition section" ;
529+ break ;
530+ case 3 :
531+ sectionName = "Process definition section" ;
532+ break ;
533+ case 4 :
534+ sectionName = "Systematics section" ;
535+ break ;
536+ }
537+
538+ symbols . push ( new vscode . DocumentSymbol (
539+ sectionName ,
540+ "" ,
541+ vscode . SymbolKind . Struct ,
542+ sectionRange ,
543+ sectionRange
544+ ) ) ;
545+ }
546+ }
547+
548+ // Handle content after last divider
549+ if ( dashLineNumbers [ dashLineNumbers . length - 1 ] < document . lineCount - 1 ) {
550+ const startLine = dashLineNumbers [ dashLineNumbers . length - 1 ] + 1 ;
551+ const endLine = document . lineCount - 1 ;
552+ const sectionRange = new vscode . Range ( startLine , 0 , endLine , document . lineAt ( endLine ) . text . length ) ;
553+ const sectionInfo = getSectionIndex ( document , startLine ) ;
554+ const adjustedSection = calculateAdjustedSection ( sectionInfo , hasShape ) ;
555+
556+ // Get section name using the same logic as CombineCompletionItemProvider
557+ let sectionName = "Other section" ;
558+ switch ( adjustedSection ) {
559+ case - 1 :
560+ sectionName = "Pre-header section" ;
561+ break ;
562+ case 0 :
563+ sectionName = "Header section" ;
564+ break ;
565+ case 1 :
566+ sectionName = "Shapes section" ;
567+ break ;
568+ case 2 :
569+ sectionName = "Channel definition section" ;
570+ break ;
571+ case 3 :
572+ sectionName = "Process definition section" ;
573+ break ;
574+ case 4 :
575+ sectionName = "Systematics section" ;
576+ break ;
577+ }
578+
579+ symbols . push ( new vscode . DocumentSymbol (
580+ sectionName ,
581+ "" ,
582+ vscode . SymbolKind . Struct ,
583+ sectionRange ,
584+ sectionRange
585+ ) ) ;
586+ }
587+ } else {
588+ // If no dividers, treat the whole document as one section
589+ const docRange = new vscode . Range ( 0 , 0 , document . lineCount - 1 , document . lineAt ( document . lineCount - 1 ) . text . length ) ;
590+ symbols . push ( new vscode . DocumentSymbol (
591+ "Datacard" ,
592+ "" ,
593+ vscode . SymbolKind . File ,
594+ docRange ,
595+ docRange
596+ ) ) ;
597+ }
598+
599+ return symbols ;
600+ }
601+ }
602+
457603function deactivate ( ) { }
458604
459605module . exports = {
0 commit comments