@@ -28,7 +28,7 @@ const remarkUrlToLink = () => {
2828 const urlRegex = / h t t p s ? : \/ \/ [ ^ \s < > ) " ] + / g
2929 const matches = node . value . match ( urlRegex )
3030
31- if ( ! matches ) {
31+ if ( ! matches || ! parent ) {
3232 return
3333 }
3434
@@ -45,25 +45,32 @@ const remarkUrlToLink = () => {
4545 const originalUrl = matches [ i ]
4646 const cleanedUrl = cleanedMatches [ i ]
4747 const removedPunctuation = originalUrl . substring ( cleanedUrl . length )
48-
48+
49+ // Create a proper link node with all required properties
4950 children . push ( {
5051 type : "link" ,
5152 url : cleanedUrl ,
53+ title : null ,
5254 children : [ { type : "text" , value : cleanedUrl } ] ,
55+ data : {
56+ hProperties : {
57+ href : cleanedUrl ,
58+ } ,
59+ } ,
5360 } )
54-
61+
5562 if ( removedPunctuation ) {
5663 children . push ( { type : "text" , value : removedPunctuation } )
5764 }
5865 }
5966 } )
6067
61- // Fix: Instead of converting the node to a paragraph (which broke things),
62- // we replace the original text node with our new nodes in the parent's children array.
68+ // Replace the original text node with our new nodes in the parent's children array.
6369 // This preserves the document structure while adding our links.
64- if ( parent ) {
65- parent . children . splice ( index , 1 , ...children )
66- }
70+ parent . children . splice ( index ! , 1 , ...children )
71+
72+ // Return SKIP to prevent visiting the newly created nodes
73+ return [ "skip" , index ! + children . length ]
6774 } )
6875 }
6976}
@@ -154,44 +161,42 @@ const MarkdownBlock = memo(({ markdown }: MarkdownBlockProps) => {
154161 rehypePlugins : [ ] ,
155162 rehypeReactOptions : {
156163 components : {
157- a : ( { href, children } : any ) => {
164+ a : ( { href, children, ...props } : any ) => {
165+ const handleClick = ( e : React . MouseEvent < HTMLAnchorElement > ) => {
166+ // Only process file:// protocol or local file paths
167+ const isLocalPath = href . startsWith ( "file://" ) || href . startsWith ( "/" ) || ! href . includes ( "://" )
168+
169+ if ( ! isLocalPath ) {
170+ return
171+ }
172+
173+ e . preventDefault ( )
174+
175+ // Handle absolute vs project-relative paths
176+ let filePath = href . replace ( "file://" , "" )
177+
178+ // Extract line number if present
179+ const match = filePath . match ( / ( .* ) : ( \d + ) ( - \d + ) ? $ / )
180+ let values = undefined
181+ if ( match ) {
182+ filePath = match [ 1 ]
183+ values = { line : parseInt ( match [ 2 ] ) }
184+ }
185+
186+ // Add ./ prefix if needed
187+ if ( ! filePath . startsWith ( "/" ) && ! filePath . startsWith ( "./" ) ) {
188+ filePath = "./" + filePath
189+ }
190+
191+ vscode . postMessage ( {
192+ type : "openFile" ,
193+ text : filePath ,
194+ values,
195+ } )
196+ }
197+
158198 return (
159- < a
160- href = { href }
161- title = { href }
162- onClick = { ( e ) => {
163- // Only process file:// protocol or local file paths
164- const isLocalPath =
165- href . startsWith ( "file://" ) || href . startsWith ( "/" ) || ! href . includes ( "://" )
166-
167- if ( ! isLocalPath ) {
168- return
169- }
170-
171- e . preventDefault ( )
172-
173- // Handle absolute vs project-relative paths
174- let filePath = href . replace ( "file://" , "" )
175-
176- // Extract line number if present
177- const match = filePath . match ( / ( .* ) : ( \d + ) ( - \d + ) ? $ / )
178- let values = undefined
179- if ( match ) {
180- filePath = match [ 1 ]
181- values = { line : parseInt ( match [ 2 ] ) }
182- }
183-
184- // Add ./ prefix if needed
185- if ( ! filePath . startsWith ( "/" ) && ! filePath . startsWith ( "./" ) ) {
186- filePath = "./" + filePath
187- }
188-
189- vscode . postMessage ( {
190- type : "openFile" ,
191- text : filePath ,
192- values,
193- } )
194- } } >
199+ < a { ...props } href = { href } onClick = { handleClick } >
195200 { children }
196201 </ a >
197202 )
0 commit comments