@@ -30,29 +30,49 @@ const remarkUrlToLink = () => {
3030 const urlRegex = / h t t p s ? : \/ \/ [ ^ \s < > ) " ] + / g
3131 const matches = node . value . match ( urlRegex )
3232
33- if ( ! matches ) {
33+ if ( ! matches || ! parent ) {
3434 return
3535 }
3636
3737 const parts = node . value . split ( urlRegex )
3838 const children : any [ ] = [ ]
39+ const cleanedMatches = matches . map ( ( url : string ) => url . replace ( / [ . , ; : ! ? ' " ] + $ / , "" ) )
3940
4041 parts . forEach ( ( part : string , i : number ) => {
4142 if ( part ) {
4243 children . push ( { type : "text" , value : part } )
4344 }
4445
45- if ( matches [ i ] ) {
46- children . push ( { type : "link" , url : matches [ i ] , children : [ { type : "text" , value : matches [ i ] } ] } )
46+ if ( cleanedMatches [ i ] ) {
47+ const originalUrl = matches [ i ]
48+ const cleanedUrl = cleanedMatches [ i ]
49+ const removedPunctuation = originalUrl . substring ( cleanedUrl . length )
50+
51+ // Create a proper link node with all required properties
52+ children . push ( {
53+ type : "link" ,
54+ url : cleanedUrl ,
55+ title : null ,
56+ children : [ { type : "text" , value : cleanedUrl } ] ,
57+ data : {
58+ hProperties : {
59+ href : cleanedUrl ,
60+ } ,
61+ } ,
62+ } )
63+
64+ if ( removedPunctuation ) {
65+ children . push ( { type : "text" , value : removedPunctuation } )
66+ }
4767 }
4868 } )
4969
50- // Fix: Instead of converting the node to a paragraph (which broke things),
51- // we replace the original text node with our new nodes in the parent's children array.
70+ // Replace the original text node with our new nodes in the parent's children array.
5271 // This preserves the document structure while adding our links.
53- if ( parent ) {
54- parent . children . splice ( index , 1 , ...children )
55- }
72+ parent . children . splice ( index ! , 1 , ...children )
73+
74+ // Return SKIP to prevent visiting the newly created nodes
75+ return [ "skip" , index ! + children . length ]
5676 } )
5777 }
5878}
@@ -169,44 +189,42 @@ const MarkdownBlock = memo(({ markdown }: MarkdownBlockProps) => {
169189 rehypePlugins : [ rehypeKatex as any ] ,
170190 rehypeReactOptions : {
171191 components : {
172- a : ( { href, children } : any ) => {
192+ a : ( { href, children, ...props } : any ) => {
193+ const handleClick = ( e : React . MouseEvent < HTMLAnchorElement > ) => {
194+ // Only process file:// protocol or local file paths
195+ const isLocalPath = href . startsWith ( "file://" ) || href . startsWith ( "/" ) || ! href . includes ( "://" )
196+
197+ if ( ! isLocalPath ) {
198+ return
199+ }
200+
201+ e . preventDefault ( )
202+
203+ // Handle absolute vs project-relative paths
204+ let filePath = href . replace ( "file://" , "" )
205+
206+ // Extract line number if present
207+ const match = filePath . match ( / ( .* ) : ( \d + ) ( - \d + ) ? $ / )
208+ let values = undefined
209+ if ( match ) {
210+ filePath = match [ 1 ]
211+ values = { line : parseInt ( match [ 2 ] ) }
212+ }
213+
214+ // Add ./ prefix if needed
215+ if ( ! filePath . startsWith ( "/" ) && ! filePath . startsWith ( "./" ) ) {
216+ filePath = "./" + filePath
217+ }
218+
219+ vscode . postMessage ( {
220+ type : "openFile" ,
221+ text : filePath ,
222+ values,
223+ } )
224+ }
225+
173226 return (
174- < a
175- href = { href }
176- title = { href }
177- onClick = { ( e ) => {
178- // Only process file:// protocol or local file paths
179- const isLocalPath =
180- href . startsWith ( "file://" ) || href . startsWith ( "/" ) || ! href . includes ( "://" )
181-
182- if ( ! isLocalPath ) {
183- return
184- }
185-
186- e . preventDefault ( )
187-
188- // Handle absolute vs project-relative paths
189- let filePath = href . replace ( "file://" , "" )
190-
191- // Extract line number if present
192- const match = filePath . match ( / ( .* ) : ( \d + ) ( - \d + ) ? $ / )
193- let values = undefined
194- if ( match ) {
195- filePath = match [ 1 ]
196- values = { line : parseInt ( match [ 2 ] ) }
197- }
198-
199- // Add ./ prefix if needed
200- if ( ! filePath . startsWith ( "/" ) && ! filePath . startsWith ( "./" ) ) {
201- filePath = "./" + filePath
202- }
203-
204- vscode . postMessage ( {
205- type : "openFile" ,
206- text : filePath ,
207- values,
208- } )
209- } } >
227+ < a { ...props } href = { href } onClick = { handleClick } >
210228 { children }
211229 </ a >
212230 )
0 commit comments