@@ -18,20 +18,25 @@ import { CancellationToken, DocumentLink, DocumentLinkProvider, Range, TextDocum
1818import { parseYamlToCTreeItem } from '../../generic/tree-item-yaml-parser' ;
1919import { CTreeItem , ETreeItemKind , ITreeItem } from '../../generic/tree-item' ;
2020import type { SolutionManager } from '../solution-manager' ;
21+ import { getCmsisPackRoot } from '../../utils/path-utils' ;
2122
2223/**
23- * Provide links for file references in solution and project files.
24+ * Provide links for file references in solution, project, and layer files as well as for *.cbuild*.yml files.
25+ *
2426 */
2527export class ReferenceLinkProvider implements DocumentLinkProvider < DocumentLink > {
28+ private static readonly REFERENCE_ITEM_TAGS = [ 'file' , 'layer' , 'project' , 'script' , 'regions' ,
29+ 'solution' , 'csolution' , 'cbuild' , 'clayer' , 'cproject' , 'cbuild-run' , 'cdefault' ] ;
30+
2631 constructor (
2732 private readonly solutionManager : SolutionManager ,
33+ private readonly cbuildFile ?: boolean ,
2834 ) {
2935 }
3036
3137 public provideDocumentLinks ( textDocument : TextDocument , _token ?: CancellationToken ) : DocumentLink [ ] {
3238 try {
3339 const topItem = parseYamlToCTreeItem ( textDocument . getText ( ) , textDocument . fileName ) ;
34-
3540 return ( topItem ?. filterItems ( item => this . isReferenceFileItem ( item ) ) ?? [ ] ) ?. flatMap ( ( item ) : DocumentLink [ ] => {
3641 const documentLink = this . treeItemToDocumentLink ( item , textDocument ) ;
3742 return documentLink ? [ documentLink ] : [ ] ;
@@ -47,15 +52,30 @@ export class ReferenceLinkProvider implements DocumentLinkProvider<DocumentLink>
4752 }
4853
4954 protected isReferenceFileItem ( item : ITreeItem < CTreeItem > ) : item is CTreeItem {
55+ if ( ! item || item . getKind ( ) !== ETreeItemKind . Scalar || ! item . getText ( ) )
56+ return false ;
5057 const tag = item . getTag ( ) ;
51- return ! ! tag && this . getReferenceItemTags ( ) . includes ( tag ) ;
58+ if ( ! tag || ! this . getReferenceItemTags ( ) . includes ( tag ) ) {
59+ return false ;
60+ }
61+ if ( this . cbuildFile ) {
62+ // in case of cbuild-idx.yml we can only expand links under 'cbuilds' section
63+ if ( tag === 'clayer' && ! item . getParent ( 'cbuilds' ) ) {
64+ return false ;
65+ }
66+ // in case of cbuild-idx.yml 'project' under 'cbuilds' is just a name, not path
67+ if ( tag === 'project' && ! ! item . getParent ( 'cbuilds' ) ) {
68+ return false ;
69+ }
70+ }
71+ return true ;
5272 }
5373
5474 protected getReferenceItemTags ( ) : string [ ] {
55- return [ 'file' , 'layer' , 'project' , 'script' , 'regions' ] ;
75+ return ReferenceLinkProvider . REFERENCE_ITEM_TAGS ;
5676 }
5777
58- private treeItemToDocumentLink ( item : ITreeItem < CTreeItem > | undefined , textDocument : TextDocument ) : DocumentLink | undefined {
78+ private treeItemToDocumentLink ( item : ITreeItem < CTreeItem > , textDocument : TextDocument ) : DocumentLink | undefined {
5979 const uri = this . getUriFromItem ( item ) ;
6080 if ( ! uri ) {
6181 return undefined ;
@@ -68,20 +88,23 @@ export class ReferenceLinkProvider implements DocumentLinkProvider<DocumentLink>
6888 }
6989
7090
71- private getUriFromItem ( item ?: ITreeItem < CTreeItem > ) : Uri | undefined {
72- if ( ! item || item . getKind ( ) !== ETreeItemKind . Scalar ) {
73- return undefined ;
74- }
91+ private getUriFromItem ( item : ITreeItem < CTreeItem > ) : Uri | undefined {
7592 let text = item . getText ( ) ;
7693 if ( ! text ) {
7794 return undefined ;
7895 }
79- const rpcData = this . solutionManager . getRpcData ( ) ;
80- const context = this . getItemContext ( item ) ;
81- if ( rpcData && context ) {
82- text = rpcData . expandString ( text , context ) ;
83- }
8496
97+ // generated files can contain references to files in packs directory
98+ if ( text . startsWith ( '${CMSIS_PACK_ROOT}' ) ) {
99+ return Uri . file ( text . replace ( '${CMSIS_PACK_ROOT}' , getCmsisPackRoot ( ) ) ) ;
100+ }
101+ if ( ! this . cbuildFile ) { // generated files have all sequences expanded
102+ const rpcData = this . solutionManager . getRpcData ( ) ;
103+ const context = this . getItemContext ( item ) ;
104+ if ( rpcData && context ) {
105+ text = rpcData . expandString ( text , context ) ;
106+ }
107+ }
85108 const resolvedPath = item . resolvePath ( text ) ;
86109 return resolvedPath ? Uri . file ( resolvedPath ) : undefined ;
87110 }
0 commit comments