Skip to content

Commit 6bacde0

Browse files
committed
links with small letter miss
1 parent c6c9244 commit 6bacde0

File tree

2 files changed

+65
-39
lines changed

2 files changed

+65
-39
lines changed

src/Parser.hs

Lines changed: 49 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,10 @@ parseInline text
362362
Just ('*', _) -> parseDecoration '*' text
363363
Just ('_', _) -> parseDecoration '_' text
364364
Just ('~', _) -> parseStrikethrough text
365-
Just ('<', _) -> parseHtmlTags text
365+
Just ('<', _) ->
366+
if T.isPrefixOf (T.pack "<u>") text || T.isPrefixOf (T.pack "</u>") text
367+
then parseHtmlTags text
368+
else parseAngleBracketLink text
366369
_ -> parsePlainText text
367370

368371
parseLinkOrCheckbox :: Text -> [MDElement]
@@ -375,37 +378,54 @@ parseLinkOrCheckbox text
375378

376379
parseBracketLink :: Text -> [MDElement]
377380
parseBracketLink text =
378-
let linkTextStart = T.tail $ T.takeWhile (/= ']') text
379-
urlStart = T.drop 2 $ T.dropWhile (/= '(') text
380-
(linkUrl, rest) = T.break (== ')') urlStart
381-
cleanUrl = T.strip linkUrl
382-
383-
-- Check for optional title
384-
(titlePart, remainingText) =
385-
case T.uncons rest of
386-
Just (_, titleText) ->
387-
let stripped = T.strip $ T.takeWhile (/= ')') titleText
388-
titleRemaining = T.drop (T.length stripped + 1) titleText
389-
in if T.isPrefixOf (T.pack "\"") stripped && T.isSuffixOf (T.pack "\"") stripped
390-
then (Just (T.init $ T.tail stripped), titleRemaining)
391-
else (Nothing, rest)
392-
Nothing -> (Nothing, rest)
393-
394-
linkTextParsed = parseInline linkTextStart
395-
nextText = T.drop 1 remainingText
396-
in case linkTextParsed of
397-
[] -> Link cleanUrl cleanUrl Nothing : parseInline nextText
398-
[PlainText t] -> Link t cleanUrl titlePart : parseInline nextText
399-
multipleElems -> Link (T.concat $ map renderPlainText multipleElems) cleanUrl titlePart : parseInline nextText
381+
let (linkText, afterText) = parseLinkText text
382+
(url, title, remaining) = parseLinkUrlAndTitle afterText
383+
in case parseInline linkText of
384+
[] -> Link url url Nothing : parseInline remaining
385+
[PlainText t] -> Link t url title : parseInline remaining
386+
multipleElems ->
387+
let renderedText = T.concat $ map renderPlainText multipleElems
388+
in Link renderedText url title : parseInline remaining
400389
where
401-
renderPlainText (PlainText t) = t
402-
renderPlainText _ = T.empty
390+
-- Parse the link text between square brackets
391+
parseLinkText :: Text -> (Text, Text)
392+
parseLinkText t =
393+
let linkTextStart = T.tail $ T.takeWhile (/= ']') t
394+
remaining = T.drop (T.length linkTextStart + 2) t
395+
in (linkTextStart, remaining)
396+
397+
-- Parse URL and optional title
398+
parseLinkUrlAndTitle :: Text -> (Text, Maybe Text, Text)
399+
parseLinkUrlAndTitle t
400+
| T.isPrefixOf (T.pack "(") t =
401+
let urlAndRest = T.tail t
402+
(rawUrl, afterUrl) = T.break (\c -> c == ')' || c == '"') urlAndRest
403+
cleanUrl = T.strip rawUrl
404+
in case T.uncons afterUrl of
405+
Just ('"', titleRest) ->
406+
let (rawTitle, afterTitle) = T.break (== '"') (T.tail titleRest)
407+
cleanTitle = unescapeTitle rawTitle
408+
finalRest = T.drop (T.length rawTitle + 2) afterTitle
409+
in (cleanUrl, Just cleanTitle, finalRest)
410+
Just (')', rest) -> (cleanUrl, Nothing, rest)
411+
_ -> (cleanUrl, Nothing, T.empty)
412+
| otherwise = (T.pack "", Nothing, t)
413+
414+
-- Unescape title, particularly handling &quot;
415+
unescapeTitle :: Text -> Text
416+
unescapeTitle =
417+
T.replace (T.pack "&quot;") (T.pack "\"")
418+
. T.replace (T.pack "&amp;") (T.pack "&")
419+
. T.replace (T.pack "&lt;") (T.pack "<")
420+
. T.replace (T.pack "&gt;") (T.pack ">")
403421

404422
parseAngleBracketLink :: Text -> [MDElement]
405-
parseAngleBracketLink text =
406-
let (link, rest) = T.break (== '>') (T.tail text)
407-
cleanLink = T.strip link
408-
in Link cleanLink cleanLink Nothing : parseInline (T.drop 1 rest)
423+
parseAngleBracketLink text
424+
| T.isPrefixOf (T.pack "<") text && T.isSuffixOf (T.pack ">") text =
425+
let link = T.init $ T.tail text
426+
cleanLink = T.strip link
427+
in Link cleanLink cleanLink Nothing : parseInline (T.drop (T.length link + 2) text)
428+
| otherwise = [PlainText text]
409429

410430
renderPlainText :: MDElement -> Text
411431
renderPlainText (PlainText t) = t

test/output.html

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -188,24 +188,30 @@ <h2 id="9f9a76a951506992fc919b8ae3f5ae15">Заголовок второго ур
188188
</li>
189189
<li>Второй пункт</li>
190190
</ol>
191-
<p>&amp;lt;https://skillbox.ru/media/code/&amp;gt;</p>
192-
<p><a href="ttps://skillbox.ru/media/">Skillbox Media</a> без подсказки</p>
193191
<p>
194-
<a href="ttps://skillbox.ru/media/ &amp;quot;Всплывающая подсказка&amp;quot;"
192+
<a href="https://skillbox.ru/media/code/">https://skillbox.ru/media/code/</a>
193+
</p>
194+
<p><a href="https://skillbox.ru/media/">Skillbox Media</a> без подсказки</p>
195+
<p>
196+
<a href="https://skillbox.ru/media/" title="�сплывающая подсказка"
195197
>Skillbox Media</a
196198
>
197-
с подсказкой
198199
</p>
199-
<p><a href="">Skillbox Media</a></p>
200-
<p><a href="">Раздел «Код»</a></p>
201-
<p><a href="">1</a> [code]: https://skillbox.ru/media/code/</p>
200+
<p><a href="">Skillbox Media</a><a href="">1</a></p>
201+
<p><a href="">Раздел «Код»</a><a href="">code</a></p>
202+
<p>
203+
<a href="">1</a>: https://skillbox.ru/media &amp;quot;Всплывающая
204+
подсказка&amp;quot; [code]: https://skillbox.ru/media/code/
205+
</p>
202206
<p>
203207
![Изображение](https://upload.wikimedia.org/wikipedia/commons/thumb/4/48/Markdown-mark.svg/1920px-Markdown-mark.svg.png
204208
&amp;quot;Логотип Markdown&amp;quot;)
205209
</p>
206210
<p>Функция `print (x)` выводит содержимое переменной ```x```.</p>
207211
<p>```</p>
208-
<h1 id="967f745ae03431977fb89c965c02c00c">include &amp;lt;stdio.h&amp;gt;</h1>
212+
<h1 id="967f745ae03431977fb89c965c02c00c">
213+
include <a href="stdio.h">stdio.h</a>
214+
</h1>
209215
<p>int main() { printf(&amp;quot;Hello, World!&amp;quot;); return 0; } ```</p>
210216
<p>```javascript let x = 12; let y = 6; console.log(x + y); ```</p>
211217
<table>
@@ -255,8 +261,8 @@ <h1 id="967f745ae03431977fb89c965c02c00c">include &amp;lt;stdio.h&amp;gt;</h1>
255261
</tbody>
256262
</table>
257263
<p>
258-
<a href="/image.png &amp;quot;Shiprock, New Mexico by Beau Rogers&amp;quot;"
264+
<a href="./image.png" title="hiprock, New Mexico by Beau Rogers"
259265
>![An old rock in the desert</a
260-
>](https://www.flickr.com/photos/beaurogers/31833779864/in/photolist-Qv3rFw-34mt9F-a9Cmfy-5Ha3Zi-9msKdv-o3hgjr-hWpUte-4WMsJ1-KUQ8N-deshUb-vssBD-6CQci6-8AFCiD-zsJWT-nNfsgB-dPDwZJ-bn9JGn-5HtSXY-6CUhAL-a4UTXB-ugPum-KUPSo-fBLNm-6CUmpy-4WMsc9-8a7D3T-83KJev-6CQ2bK-nNusHJ-a78rQH-nw3NvT-7aq2qf-8wwBso-3nNceh-ugSKP-4mh4kh-bbeeqH-a7biME-q3PtTf-brFpgb-cg38zw-bXMZc-nJPELD-f58Lmo-bXMYG-bz8AAi-bxNtNT-bXMYi-bXMY6-bXMYv)
266+
>aurogers/31833779864/in/photolist-Qv3rFw-34mt9F-a9Cmfy-5Ha3Zi-9msKdv-o3hgjr-hWpUte-4WMsJ1-KUQ8N-deshUb-vssBD-6CQci6-8AFCiD-zsJWT-nNfsgB-dPDwZJ-bn9JGn-5HtSXY-6CUhAL-a4UTXB-ugPum-KUPSo-fBLNm-6CUmpy-4WMsc9-8a7D3T-83KJev-6CQ2bK-nNusHJ-a78rQH-nw3NvT-7aq2qf-8wwBso-3nNceh-ugSKP-4mh4kh-bbeeqH-a7biME-q3PtTf-brFpgb-cg38zw-bXMZc-nJPELD-f58Lmo-bXMYG-bz8AAi-bxNtNT-bXMYi-bXMY6-bXMYv)
261267
</p>
262268
<p>\\ \` \_ \* \{ \} \[ \] \&amp;lt; \&amp;gt; \( \) # \# \! \|</p>

0 commit comments

Comments
 (0)