@@ -9,7 +9,7 @@ import { Slugifier } from '../slugify';
9
9
import { TableOfContents , TocEntry } from '../tableOfContents' ;
10
10
import { Disposable } from '../util/dispose' ;
11
11
import { MdWorkspaceContents , SkinnyTextDocument } from '../workspaceContents' ;
12
- import { InternalLinkTarget , LinkData , LinkTarget , MdLinkProvider } from './documentLinkProvider' ;
12
+ import { DefinitionLinkTarget , InternalLinkTarget , LinkData , LinkTarget , MdLinkProvider } from './documentLinkProvider' ;
13
13
import { MdWorkspaceCache } from './workspaceCache' ;
14
14
15
15
@@ -20,10 +20,53 @@ function isLinkToHeader(target: LinkTarget, header: TocEntry, headerDocument: vs
20
20
}
21
21
22
22
23
- export interface MdReference {
23
+ /**
24
+ * A link in a markdown file.
25
+ */
26
+ interface MdLinkReference {
27
+ readonly kind : 'link' ;
24
28
readonly isTriggerLocation : boolean ;
25
29
readonly isDefinition : boolean ;
26
30
readonly location : vscode . Location ;
31
+
32
+ readonly fragmentLocation : vscode . Location | undefined ;
33
+ }
34
+
35
+ /**
36
+ * A header in a markdown file.
37
+ */
38
+ interface MdHeaderReference {
39
+ readonly kind : 'header' ;
40
+
41
+ readonly isTriggerLocation : boolean ;
42
+ readonly isDefinition : boolean ;
43
+
44
+ /**
45
+ * The range of the header.
46
+ *
47
+ * In `# a b c #` this would be the range of `# a b c #`
48
+ */
49
+ readonly location : vscode . Location ;
50
+
51
+ /**
52
+ * The range of the header text itself.
53
+ *
54
+ * In `# a b c #` this would be the range of `a b c`
55
+ */
56
+ readonly headerTextLocation : vscode . Location ;
57
+ }
58
+
59
+ export type MdReference = MdLinkReference | MdHeaderReference ;
60
+
61
+
62
+ function getFragmentLocation ( link : LinkData ) : vscode . Location | undefined {
63
+ const index = link . sourceText . indexOf ( '#' ) ;
64
+ if ( index < 0 ) {
65
+ return undefined ;
66
+ }
67
+ return new vscode . Location ( link . sourceResource , link . sourceRange . with ( {
68
+ start : link . sourceRange . start . translate ( { characterDelta : index + 1 } ) ,
69
+ } ) ) ;
27
70
}
28
71
29
72
export class MdReferencesProvider extends Disposable implements vscode . ReferenceProvider {
@@ -70,23 +113,29 @@ export class MdReferencesProvider extends Disposable implements vscode.Reference
70
113
71
114
const line = document . lineAt ( header . line ) ;
72
115
references . push ( {
116
+ kind : 'header' ,
73
117
isTriggerLocation : true ,
74
118
isDefinition : true ,
75
119
location : new vscode . Location ( document . uri , new vscode . Range ( header . line , 0 , header . line , line . text . length ) ) ,
120
+ headerTextLocation : header . headerTextLocation
76
121
} ) ;
77
122
78
123
for ( const link of links ) {
79
124
if ( isLinkToHeader ( link . target , header , document . uri , this . slugifier ) ) {
80
125
references . push ( {
126
+ kind : 'link' ,
81
127
isTriggerLocation : false ,
82
128
isDefinition : false ,
83
- location : new vscode . Location ( link . sourceResource , link . sourceRange )
129
+ location : new vscode . Location ( link . sourceResource , link . sourceRange ) ,
130
+ fragmentLocation : getFragmentLocation ( link ) ,
84
131
} ) ;
85
132
} else if ( link . target . kind === 'definition' && isLinkToHeader ( link . target . target , header , document . uri , this . slugifier ) ) {
86
133
references . push ( {
134
+ kind : 'link' ,
87
135
isTriggerLocation : false ,
88
136
isDefinition : false ,
89
- location : new vscode . Location ( link . sourceResource , link . sourceRange )
137
+ location : new vscode . Location ( link . sourceResource , link . sourceRange ) ,
138
+ fragmentLocation : getFragmentLocation ( link ) ,
90
139
} ) ;
91
140
}
92
141
}
@@ -101,6 +150,10 @@ export class MdReferencesProvider extends Disposable implements vscode.Reference
101
150
}
102
151
103
152
private async getReferencesToLink ( sourceLink : LinkData ) : Promise < MdReference [ ] > {
153
+ if ( sourceLink . target . kind === 'definition' ) {
154
+ return this . getReferencesToLink ( this . getInnerLink ( sourceLink , sourceLink . target ) ) ;
155
+ }
156
+
104
157
const allLinksInWorkspace = ( await this . _linkCache . getAll ( ) ) . flat ( ) ;
105
158
106
159
if ( sourceLink . target . kind === 'reference' ) {
@@ -131,14 +184,20 @@ export class MdReferencesProvider extends Disposable implements vscode.Reference
131
184
const entry = toc . lookup ( sourceLink . target . fragment ) ;
132
185
if ( entry ) {
133
186
references . push ( {
187
+ kind : 'header' ,
134
188
isTriggerLocation : false ,
135
189
isDefinition : true ,
136
190
location : entry . headerLocation ,
191
+ headerTextLocation : entry . headerTextLocation
137
192
} ) ;
138
193
}
139
194
}
140
195
141
- for ( const link of allLinksInWorkspace ) {
196
+ for ( let link of allLinksInWorkspace ) {
197
+ if ( link . target . kind === 'definition' ) {
198
+ link = this . getInnerLink ( link , link . target ) ;
199
+ }
200
+
142
201
if ( link . target . kind !== 'internal' ) {
143
202
continue ;
144
203
}
@@ -155,19 +214,23 @@ export class MdReferencesProvider extends Disposable implements vscode.Reference
155
214
if ( sourceLink . target . fragment ) {
156
215
if ( this . slugifier . fromHeading ( link . target . fragment ) . equals ( this . slugifier . fromHeading ( sourceLink . target . fragment ) ) ) {
157
216
references . push ( {
217
+ kind : 'link' ,
158
218
isTriggerLocation,
159
219
isDefinition : false ,
160
220
location : new vscode . Location ( link . sourceResource , link . sourceRange ) ,
221
+ fragmentLocation : getFragmentLocation ( link ) ,
161
222
} ) ;
162
223
}
163
224
} else { // Triggered on a link without a fragment so we only require matching the file and ignore fragments
164
225
165
226
// But exclude cases where the file is referencing itself
166
227
if ( link . sourceResource . fsPath !== targetDoc . uri . fsPath ) {
167
228
references . push ( {
229
+ kind : 'link' ,
168
230
isTriggerLocation,
169
231
isDefinition : false ,
170
232
location : new vscode . Location ( link . sourceResource , link . sourceRange ) ,
233
+ fragmentLocation : getFragmentLocation ( link ) ,
171
234
} ) ;
172
235
}
173
236
}
@@ -176,6 +239,15 @@ export class MdReferencesProvider extends Disposable implements vscode.Reference
176
239
return references ;
177
240
}
178
241
242
+ private getInnerLink ( sourceLink : LinkData , target : DefinitionLinkTarget ) : LinkData {
243
+ return {
244
+ sourceText : sourceLink . sourceText , // This is not correct
245
+ sourceResource : sourceLink . sourceResource ,
246
+ sourceRange : sourceLink . sourceRange ,
247
+ target : target . target ,
248
+ } ;
249
+ }
250
+
179
251
private * getReferencesToReferenceLink ( allLinks : Iterable < LinkData > , sourceLink : LinkData ) : Iterable < MdReference > {
180
252
if ( sourceLink . target . kind !== 'reference' ) {
181
253
return ;
@@ -186,9 +258,11 @@ export class MdReferencesProvider extends Disposable implements vscode.Reference
186
258
if ( link . target . ref === sourceLink . target . ref && link . sourceResource . fsPath === sourceLink . sourceResource . fsPath ) {
187
259
const isTriggerLocation = sourceLink . sourceResource . fsPath === link . sourceResource . fsPath && sourceLink . sourceRange . isEqual ( link . sourceRange ) ;
188
260
yield {
261
+ kind : 'link' ,
189
262
isTriggerLocation,
190
- isDefinition : false ,
191
- location : new vscode . Location ( sourceLink . sourceResource , link . sourceRange )
263
+ isDefinition : link . target . kind === 'definition' ,
264
+ location : new vscode . Location ( sourceLink . sourceResource , link . sourceRange ) ,
265
+ fragmentLocation : getFragmentLocation ( link ) ,
192
266
} ;
193
267
}
194
268
}
0 commit comments