mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-11-04 08:37:30 +00:00
core, ui: markdown links in parentheses, keep single line breaks (#7940)
* core: tests of markdown links in parentheses and single line breaks * core, ui: markdown links in parentheses, keep single line breaks * core: test of a hyperlink text across lines with the address as a link * ci: desktop references with **bold** in the markdown help * ci: iOS references with **bold** in the markdown help
This commit is contained in:
1 parent
3bdecd63f8
commit
b7bae8c47e
17 files changed
+171
-72
No files matched your search
@@ -309,7 +309,7 @@ markdownInfo =
|
||||
map
|
||||
styleMarkdown
|
||||
[ green "Markdown:",
|
||||
indent <> highlight "*bold* " <> " - " <> markdown (Bold $ BoolDef True) "bold text",
|
||||
indent <> highlight "**bold** " <> " - " <> markdown (Bold $ BoolDef False) "bold text",
|
||||
indent <> highlight "_italic_ " <> " - " <> markdown Italic "italic text" <> " (shown as underlined)",
|
||||
indent <> highlight "~strikethrough~" <> " - " <> markdown StrikeThrough "strikethrough text" <> " (shown as inverse)",
|
||||
indent <> highlight "`code snippet` " <> " - " <> markdown Snippet "a + b // no *markdown* here",
|
||||
|
||||
@@ -486,20 +486,35 @@ markdownP = joinMarkdown <$> A.many' fragmentP
|
||||
wordP :: Parser Markdown
|
||||
wordP = wordMD . T.concat <$> A.many' (A.takeWhile1 (\c -> c /= ' ' && c /= '\n' && c /= '\\') <|> (notP escapeP *> A.string "\\"))
|
||||
wordMD :: Text -> Markdown
|
||||
wordMD s
|
||||
| T.null s = unmarked s
|
||||
| isUri s' = case strDecode $ encodeUtf8 s of
|
||||
Right cLink -> res $ markdown (simplexUriFormat Nothing cLink) s'
|
||||
Left _ -> case parseUri $ encodeUtf8 s' of
|
||||
Right _ -> res $ markdown Uri s'
|
||||
Left _ -> unmarked s
|
||||
| isDomain s' = res $ markdown Uri s'
|
||||
| isEmail s' = res $ markdown Email s'
|
||||
| otherwise = unmarked s
|
||||
wordMD s = fromMaybe (unmarked s) $ linkMD s <|> linkAfterParen
|
||||
where
|
||||
punct = T.takeWhileEnd isPunctuation' s
|
||||
s' = T.dropWhileEnd isPunctuation' s
|
||||
linkAfterParen = case T.breakOn "(" s of
|
||||
(before, after)
|
||||
| not (T.null after) ->
|
||||
let (parens, rest) = T.span (== '(') after
|
||||
in (unmarked (before <> parens) <>) <$> linkMD rest
|
||||
_ -> Nothing
|
||||
linkMD :: Text -> Maybe Markdown
|
||||
linkMD s
|
||||
| isUri s' = case strDecode $ encodeUtf8 s' of
|
||||
Right cLink -> Just $ res $ markdown (simplexUriFormat Nothing cLink) s'
|
||||
Left _ -> case parseUri $ encodeUtf8 s' of
|
||||
Right _ -> Just $ res $ markdown Uri s'
|
||||
Left _ -> Nothing
|
||||
| isDomain s' = Just $ res $ markdown Uri s'
|
||||
| isEmail s' = Just $ res $ markdown Email s'
|
||||
| otherwise = Nothing
|
||||
where
|
||||
(s', punct) = T.splitAt (T.length s - linkEndLength s) s
|
||||
res md' = if T.null punct then md' else md' :|: unmarked punct
|
||||
linkEndLength :: Text -> Int
|
||||
linkEndLength s = go (T.count ")" s - T.count "(" s) s 0
|
||||
where
|
||||
go unmatched t n = case T.unsnoc t of
|
||||
Just (t', c)
|
||||
| isPunctuation' c -> go unmatched t' (n + 1)
|
||||
| c == ')' && unmatched > 0 -> go (unmatched - 1) t' (n + 1)
|
||||
_ -> n
|
||||
isPunctuation' = \case
|
||||
'/' -> False
|
||||
')' -> False
|
||||
@@ -654,7 +669,7 @@ listItemP :: Parser MarkdownList
|
||||
listItemP = do
|
||||
(num, syntax) <- listMarkP
|
||||
l <- lineTextP
|
||||
ls <- A.many' $ (\br ind l' -> (br, [markupText Indent ind | not (T.null ind)], l')) <$> lineEndP <* paragraphLineP <*> A.takeWhile isIndentChar <*> lineTextP
|
||||
ls <- A.many' $ (\br ind l' -> (br, [markupText Indent ind], l')) <$> lineEndP <* paragraphLineP <*> A.takeWhile1 isIndentChar <*> lineTextP
|
||||
pure $ markupText (ListMark num) syntax : inlineLines l ls
|
||||
|
||||
listMarkP :: Parser (Maybe Text, Text)
|
||||
@@ -675,17 +690,16 @@ quoteP :: Parser MarkdownList
|
||||
quoteP = do
|
||||
leading <- A.many' $ (\l br -> [markupText QuoteMark l, markupText HardBreak br]) <$> blankQuoteLineP <*> lineEndP
|
||||
(mark, l) <- quoteTextP
|
||||
ls <- nextLinesP True
|
||||
ls <- nextLinesP
|
||||
pure $ concat leading <> (markupText QuoteMark mark : inlineLines l ls)
|
||||
where
|
||||
quoteTextP = (,) <$> quoteMarkP <* hasTextP <*> lineTextP
|
||||
nextLinesP afterText = A.option [] $ do
|
||||
nextLinesP = A.option [] $ do
|
||||
br <- lineEndP
|
||||
(syntax, l, isText) <- quoteLineP <|> blankLineP <|> (if afterText then lazyLineP else mzero)
|
||||
((br, syntax, l) :) <$> nextLinesP isText
|
||||
quoteLineP = (\(m, l) -> ([markupText QuoteMark m], l, True)) <$> quoteTextP
|
||||
blankLineP = (\l -> ([markupText QuoteMark l], "", False)) <$> blankQuoteLineP
|
||||
lazyLineP = ([],,True) <$> (notP quoteMarkP *> paragraphLineP *> lineTextP)
|
||||
(syntax, l) <- quoteLineP <|> blankLineP
|
||||
((br, syntax, l) :) <$> nextLinesP
|
||||
quoteLineP = (\(m, l) -> ([markupText QuoteMark m], l)) <$> quoteTextP
|
||||
blankLineP = (\l -> ([markupText QuoteMark l], "")) <$> blankQuoteLineP
|
||||
|
||||
quoteMarkP :: Parser Text
|
||||
quoteMarkP = do
|
||||
@@ -728,7 +742,7 @@ breakAfter :: Text -> Text -> (Text, FormattedText)
|
||||
breakAfter l br
|
||||
| T.length spaces >= 2 = (T.dropEnd (T.length spaces) l, markupText HardBreak (spaces <> br))
|
||||
| odd (T.length $ T.takeWhileEnd (== '\\') l) = (T.dropEnd 1 l, markupText HardBreak ("\\" <> br))
|
||||
| otherwise = (l, markupText SoftBreak br)
|
||||
| otherwise = (l, markupText HardBreak br)
|
||||
where
|
||||
spaces = T.takeWhileEnd (== ' ') l
|
||||
|
||||
|
||||
Reference in new issue
Block a user