clx-browser

[ACTIVE] a smol browser based off of circumflex
git clone git://git.figbert.com/clx-browser.git
Log | Files | Refs | README | LICENSE

commit 26049a332d66aaf2aab562c3bfab269dc65ede21
parent c7db75a6ab018f6138be9822b84fbf5d2ba8c606
Author: FIGBERT <figbert@figbert.com>
Date:   Fri, 29 Jul 2022 20:49:45 -0700

Reorient around Charm libraries

Markdown rendering is now handled by Glamour, which works with links and
is highly customizable. A future commit will introduce a custom
stylesheet to make rendering look as similar to the original circumflex
aesthetic as possible.

The header portion has also been simplified with Lip Gloss. The title is
now included in the bordered area, and spacing is handled in the primary
style.

Several submodules were no longer used after these changes, and have
thus been deleted.

Diffstat:
Dconstants/margins/margins.go | 8--------
Dconstants/unicode/unicode.go | 6------
Mgo.mod | 8++------
Mgo.sum | 8--------
Mmain.go | 49++++++++++++++++++++++++++++++++++++++++---------
Dmarkdown/markdown.go | 27---------------------------
Dmarkdown/parser/parser.go | 256-------------------------------------------------------------------------------
Dmarkdown/postprocessor/bbc.go | 52----------------------------------------------------
Dmarkdown/postprocessor/filter/filter.go | 173-------------------------------------------------------------------------------
Dmarkdown/postprocessor/postprocessor.go | 71-----------------------------------------------------------------------
Dmarkdown/postprocessor/rules.go | 129-------------------------------------------------------------------------------
Dmarkdown/postprocessor/wikipedia.go | 17-----------------
Dmarkdown/preprocessor/preprocessor.go | 26--------------------------
Dmarkdown/renderer/renderer.go | 495-------------------------------------------------------------------------------
Dmeta/meta.go | 31-------------------------------
Mreader/reader.go | 55+------------------------------------------------------
Dstrip-ansi/strip-ansi.go | 14--------------
Dsyntax/syntax.go | 45---------------------------------------------
18 files changed, 43 insertions(+), 1427 deletions(-)

diff --git a/constants/margins/margins.go b/constants/margins/margins.go @@ -1,8 +0,0 @@ -package margins - -const ( - MainViewLeftMargin = 7 - MainViewRightMarginPageCounter = 5 - CommentSectionLeftMargin = 2 - ReaderViewLeftMargin = 2 -) diff --git a/constants/unicode/unicode.go b/constants/unicode/unicode.go @@ -1,6 +0,0 @@ -package unicode - -const ( - ZeroWidthSpace = "\u200b" - NoBreakSpace = " " -) diff --git a/go.mod b/go.mod @@ -4,18 +4,13 @@ go 1.18 require ( github.com/JohannesKaufmann/html-to-markdown v1.3.5 - github.com/MichaelMure/go-term-text v0.3.1 - github.com/PuerkitoBio/goquery v1.8.0 github.com/charmbracelet/glamour v0.5.0 github.com/charmbracelet/lipgloss v0.5.0 - github.com/go-resty/resty/v2 v2.7.0 github.com/go-shiori/go-readability v0.0.0-20220215145315-dd6828d2f09b - github.com/logrusorgru/aurora/v3 v3.0.0 - github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0 - github.com/wayneashleyberry/terminal-dimensions v1.1.0 ) require ( + github.com/PuerkitoBio/goquery v1.8.0 // indirect github.com/alecthomas/chroma v0.10.0 // indirect github.com/andybalholm/cascadia v1.3.1 // indirect github.com/aymerick/douceur v0.2.0 // indirect @@ -28,6 +23,7 @@ require ( github.com/mattn/go-runewidth v0.0.13 // indirect github.com/microcosm-cc/bluemonday v1.0.17 // indirect github.com/muesli/reflow v0.3.0 // indirect + github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/sirupsen/logrus v1.8.1 // indirect diff --git a/go.sum b/go.sum @@ -2,8 +2,6 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/JohannesKaufmann/html-to-markdown v1.3.5 h1:FrP3D5IqpxkNOk97TvbFduSo0JQKs/ZpgjuxpmAEFRA= github.com/JohannesKaufmann/html-to-markdown v1.3.5/go.mod h1:JNSClIRYICFDiFhw6RBhBeWGnMSSKVZ6sPQA+TK4tyM= -github.com/MichaelMure/go-term-text v0.3.1 h1:Kw9kZanyZWiCHOYu9v/8pWEgDQ6UVN9/ix2Vd2zzWf0= -github.com/MichaelMure/go-term-text v0.3.1/go.mod h1:QgVjAEDUnRMlzpS6ky5CGblux7ebeiLnuy9dAaFZu8o= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= github.com/PuerkitoBio/goquery v1.8.0 h1:PJTF7AmFCFKk1N6V6jmKfrNH9tV5pNE6lZMkG0gta/U= @@ -45,8 +43,6 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY= -github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I= github.com/go-shiori/dom v0.0.0-20210627111528-4e4722cd0d65 h1:zx4B0AiwqKDQq+AgqxWeHwbbLJQeidq20hgfP+aMNWI= github.com/go-shiori/dom v0.0.0-20210627111528-4e4722cd0d65/go.mod h1:NPO1+buE6TYOWhUI98/hXLHHJhunIpXRuvDN4xjkCoE= github.com/go-shiori/go-readability v0.0.0-20220215145315-dd6828d2f09b h1:yrGomo5CP7IvXwSwKbDeaJkhwa4BxfgOO/s1V7iOQm4= @@ -82,8 +78,6 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/logrusorgru/aurora/v3 v3.0.0 h1:R6zcoZZbvVcGMvDCKo45A9U/lzYyzl5NfYIvznmDfE4= -github.com/logrusorgru/aurora/v3 v3.0.0/go.mod h1:vsR12bk5grlLvLXAYrBsb5Oc/N+LxAlxggSjiwMnCUc= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -156,8 +150,6 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/wayneashleyberry/terminal-dimensions v1.1.0 h1:EB7cIzBdsOzAgmhTUtTTQXBByuPheP/Zv1zL2BRPY6g= -github.com/wayneashleyberry/terminal-dimensions v1.1.0/go.mod h1:2lc/0eWCObmhRczn2SdGSQtgBooLUzIotkkEGXqghyg= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.2.0/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= diff --git a/main.go b/main.go @@ -1,15 +1,15 @@ package main import ( + "fmt" "os" "os/exec" "strings" - "git.figbert.com/clx-browser/constants/unicode" - "git.figbert.com/clx-browser/markdown/parser" - "git.figbert.com/clx-browser/markdown/postprocessor" - "git.figbert.com/clx-browser/markdown/renderer" "git.figbert.com/clx-browser/reader" + + "github.com/charmbracelet/glamour" + "github.com/charmbracelet/lipgloss" ) func main() { @@ -20,14 +20,17 @@ func main() { panic(err) } - blocks := parser.Parse(article) - header := renderer.CreateHeader(title, url, 70) - renderedArticle := renderer.ToString(blocks, 70, " ▎") - renderedArticle = postprocessor.Process(header+renderedArticle, url) + header := getReaderModeMetaBlock(title, url, 72) + + markdown, err := glamour.Render(article, "dark") + if err != nil { + panic(err) + } + + renderedArticle := header + markdown command := exec.Command("less", "--RAW-CONTROL-CHARS", - "--pattern="+unicode.ZeroWidthSpace, "--ignore-case", "--tilde", "--use-color", @@ -41,3 +44,31 @@ func main() { panic(err) } } + +func getReaderModeMetaBlock(title string, url string, lineWidth int) string { + style := lipgloss.NewStyle(). + BorderStyle(lipgloss.RoundedBorder()). + PaddingLeft(1). + PaddingRight(1). + MarginLeft(1). + MarginTop(1). + MarginBottom(1). + Width(lineWidth) + bold := lipgloss.NewStyle().Bold(true) + blue := lipgloss.NewStyle().Foreground(lipgloss.Color("32")) + green := lipgloss.NewStyle().Foreground(lipgloss.Color("34")) + + urlRunes := []rune(url) + if len(urlRunes) > lineWidth-2 { + url = string(append(urlRunes[:lineWidth-3], '…')) + } + + return style.Render( + fmt.Sprintf( + "%s\n%s\n%s", + bold.Render(title), + blue.Render(url), + green.Render("Reader Mode"), + ), + ) +} diff --git a/markdown/markdown.go b/markdown/markdown.go @@ -1,27 +0,0 @@ -package markdown - -const ( - Text = 0 - Image = 1 - H1 = 2 - H2 = 3 - H3 = 4 - H4 = 5 - H5 = 6 - H6 = 7 - Quote = 8 - Code = 9 - List = 10 - Table = 11 - Divider = 12 - - ItalicStart = "[CLX-ITALIC]" - ItalicStop = "[CLX-ITALIC-STOP]" - BoldStart = "[CLX-BOLD]" - BoldStop = "[CLX-BOLD-STOP]" -) - -type Block struct { - Kind int - Text string -} diff --git a/markdown/parser/parser.go b/markdown/parser/parser.go @@ -1,256 +0,0 @@ -package parser - -import ( - "errors" - "regexp" - "strings" - - "git.figbert.com/clx-browser/markdown" -) - -func Parse(text string) []*markdown.Block { - var blocks []*markdown.Block - - enDash := "–" - emDash := "—" - normalDash := "-" - - // en- and em-dashes are occasionally used or list items. - // converting them to normal dashes lets us parse more list items. - text = strings.ReplaceAll(text, enDash, normalDash) - text = strings.ReplaceAll(text, emDash, normalDash) - - text = strings.ReplaceAll(text, markdown.BoldStart, "") - text = strings.ReplaceAll(text, markdown.BoldStop, "") - - lines := strings.Split(text+"\n", "\n") - temp := new(tempBuffer) - - isInsideQuote := false - isInsideCode := false - isInsideText := false - isInsideList := false - isInsideTable := false - - for _, line := range lines { - lineWithoutFormatting := strings.TrimLeft(line, " ") - lineWithoutFormatting = strings.ReplaceAll(line, markdown.BoldStart, "") - lineWithoutFormatting = strings.ReplaceAll(line, markdown.ItalicStart, "") - - if isInsideCode { - if strings.HasPrefix(lineWithoutFormatting, "```") { - isInsideCode = false - - appendedBlocks, err := appendNonEmptyBuffer(temp, blocks) - if err == nil { - blocks = appendedBlocks - } - - temp.reset() - - continue - } - - temp.append("\n" + line) - - continue - } - - if line == "" { - appendedBlocks, err := appendNonEmptyBuffer(temp, blocks) - if err == nil { - blocks = appendedBlocks - } - - temp.reset() - - isInsideQuote = false - isInsideText = false - isInsideList = false - isInsideTable = false - - continue - } - - if isInsideTable { - temp.append("\n" + line) - - continue - } - - if isInsideText { - temp.append(" " + line) - - continue - } - - if isInsideList { - temp.append("\n" + line) - - continue - } - - if isInsideQuote { - line = strings.TrimPrefix(line, ">") - line = strings.TrimPrefix(line, " ") - - temp.append("\n" + line) - - continue - } - - switch { - case strings.HasPrefix(lineWithoutFormatting, `![`): - temp.kind = markdown.Image - temp.text = line - - case strings.HasPrefix(lineWithoutFormatting, "> "): - temp.kind = markdown.Quote - temp.text = strings.TrimPrefix(line, "> ") - - isInsideQuote = true - - case strings.HasPrefix(lineWithoutFormatting, "```"): - temp.kind = markdown.Code - temp.text = "" - - isInsideCode = true - - case isListItem(lineWithoutFormatting): - if isSameTypeAsPreviousItem(markdown.List, blocks) { - lastItem := len(blocks) - 1 - - temp.kind = markdown.List - temp.text = blocks[lastItem].Text + "\n" + line - - blocks = RemoveIndex(blocks, lastItem) - isInsideList = true - - continue - } - - temp.kind = markdown.List - temp.text = line - - isInsideList = true - - case strings.HasPrefix(lineWithoutFormatting, "|"): - if isSameTypeAsPreviousItem(markdown.Table, blocks) { - lastItem := len(blocks) - 1 - - temp.kind = markdown.Table - temp.text = blocks[lastItem].Text + "\n" + line - - blocks = RemoveIndex(blocks, lastItem) - isInsideTable = true - - continue - } - - temp.kind = markdown.Table - temp.text = line - - isInsideTable = true - - case strings.HasPrefix(lineWithoutFormatting, "* * *"): - temp.kind = markdown.Divider - temp.text = line - - case strings.HasPrefix(lineWithoutFormatting, "# "): - temp.kind = markdown.H1 - temp.text = lineWithoutFormatting - - isInsideText = true - - case strings.HasPrefix(lineWithoutFormatting, "## "): - temp.kind = markdown.H2 - temp.text = lineWithoutFormatting - - isInsideText = true - - case strings.HasPrefix(lineWithoutFormatting, "### "): - temp.kind = markdown.H3 - temp.text = lineWithoutFormatting - - isInsideText = true - - case strings.HasPrefix(lineWithoutFormatting, "#### "): - temp.kind = markdown.H4 - temp.text = lineWithoutFormatting - - isInsideText = true - - case strings.HasPrefix(lineWithoutFormatting, "##### "): - temp.kind = markdown.H5 - temp.text = lineWithoutFormatting - - isInsideText = true - - case strings.HasPrefix(lineWithoutFormatting, "###### "): - temp.kind = markdown.H6 - temp.text = lineWithoutFormatting - - isInsideText = true - - default: - temp.kind = markdown.Text - temp.text = line - - isInsideText = true - } - } - - return blocks -} - -func RemoveIndex(s []*markdown.Block, index int) []*markdown.Block { - return append(s[:index], s[index+1:]...) -} - -func isListItem(text string) bool { - if text == "" { - return false - } - - exp := regexp.MustCompile(`^\s*(-|\d+\. )`) - listToken := exp.FindString(text) - - return listToken != "" -} - -func isSameTypeAsPreviousItem(itemType int, blocks []*markdown.Block) bool { - if len(blocks) == 0 { - return false - } - - previousItem := len(blocks) - 1 - - return blocks[previousItem].Kind == itemType -} - -func appendNonEmptyBuffer(temp *tempBuffer, blocks []*markdown.Block) ([]*markdown.Block, error) { - if temp.kind == markdown.Text && temp.text == "" { - return nil, errors.New("buffer is empty") - } - - b := markdown.Block{ - Kind: temp.kind, - Text: temp.text, - } - - return append(blocks, &b), nil -} - -type tempBuffer struct { - kind int - text string -} - -func (b *tempBuffer) reset() { - b.kind = 0 - b.text = "" -} - -func (b *tempBuffer) append(text string) { - b.text += text -} diff --git a/markdown/postprocessor/bbc.go b/markdown/postprocessor/bbc.go @@ -1,52 +0,0 @@ -package postprocessor - -import ( - "strings" - - "git.figbert.com/clx-browser/markdown/postprocessor/filter" - - . "github.com/logrusorgru/aurora/v3" -) - -func processBBC(text string) string { - lines := strings.Split(text, "\n") - output := "" - - for i, line := range lines { - isOnFirstOrLastLine := i == 0 || i == len(lines)-1 - lineNoLeadingWhitespace := strings.TrimLeft(line, " ") - - if len(lineNoLeadingWhitespace) == 1 { - continue - } - - if strings.Contains(line, "(Image credit: ") { - continue - } - - if isOnFirstOrLastLine { - output += line + "\n" - - continue - } - - if filter.IsOnLineBeforeTargetEquals([]string{"--"}, lines, i) || - filter.IsOnLineBeforeTargetEquals([]string{"You may also be interested in:"}, lines, i) { - output += "\n" - - break - } - - image := Cyan("Image: ").Faint().String() - line = strings.ReplaceAll(line, "image source", image) - - caption := Yellow("Caption: ").Faint().String() - line = strings.ReplaceAll(line, "image caption", caption) - - output += line + "\n" - } - - output = strings.ReplaceAll(output, "\n\n\n", "\n\n") - - return output -} diff --git a/markdown/postprocessor/filter/filter.go b/markdown/postprocessor/filter/filter.go @@ -1,173 +0,0 @@ -package filter - -import ( - "strings" - - "git.figbert.com/clx-browser/constants/unicode" - ansi "git.figbert.com/clx-browser/strip-ansi" -) - -type RuleSet struct { - skipLineContains []string - skipLineEquals []string - skipParContains []string - skipParEquals []string - endLineContains []string - endLineEquals []string -} - -func (rs *RuleSet) Filter(text string) string { - paragraphs := strings.Split(text, "\n\n") - output := "" - - output = filterByParagraph(paragraphs, output, rs) - - lines := strings.Split(output, "\n") - output = "" - - output = filterByLine(lines, output, rs) - - output = strings.ReplaceAll(output, "\n\n\n\n", "\n\n\n") - output = strings.ReplaceAll(output, "\n\n\n", "\n\n") - output = strings.ReplaceAll(output, "\n\n\n", "\n\n") - output = strings.ReplaceAll(output, "\n\n\n", "\n\n") - - return output -} - -func filterByLine(lines []string, output string, rs *RuleSet) string { - for i, line := range lines { - isOnFirstOrLastLine := i == 0 || i == len(lines)-1 - lineNoLeadingWhitespace := strings.TrimLeft(line, " ") - - if len(lineNoLeadingWhitespace) == 1 { - continue - } - - if equals(rs.skipLineEquals, line) || - contains(rs.skipLineContains, line) { - continue - } - - if isOnFirstOrLastLine { - output += line + "\n" - - continue - } - - if IsOnLineBeforeTargetEquals(rs.endLineEquals, lines, i) || - IsOnLineBeforeTargetContains(rs.endLineContains, lines, i) { - output += "\n" - - break - } - - output += line + "\n" - } - - return output -} - -func filterByParagraph(paragraphs []string, output string, rs *RuleSet) string { - for i, paragraph := range paragraphs { - isOnFirstOrLastParagraph := i == 0 || i == len(paragraphs)-1 - parNoLeadingWhitespace := strings.TrimLeft(paragraph, " ") - - if len(parNoLeadingWhitespace) == 1 { - continue - } - - if equals(rs.skipParEquals, paragraph) || - contains(rs.skipParContains, paragraph) { - continue - } - - if isOnFirstOrLastParagraph { - output += paragraph + "\n\n" - - continue - } - - output += paragraph + "\n\n" - } - - return output -} - -func (rs *RuleSet) SkipLineContains(text string) { - rs.skipLineContains = append(rs.skipLineContains, text) -} - -func (rs *RuleSet) SkipLineEquals(text string) { - rs.skipLineEquals = append(rs.skipLineEquals, text) -} - -func (rs *RuleSet) SkipParContains(text string) { - rs.skipParContains = append(rs.skipParContains, text) -} - -func (rs *RuleSet) SkipParEquals(text string) { - rs.skipParEquals = append(rs.skipParEquals, text) -} - -func (rs *RuleSet) EndBeforeLineContains(text string) { - rs.endLineContains = append(rs.endLineContains, text) -} - -func (rs *RuleSet) EndBeforeLineEquals(text string) { - rs.endLineEquals = append(rs.endLineEquals, text) -} - -func equals(targets []string, line string) bool { - for _, target := range targets { - line = ansi.Strip(line) - line = strings.TrimSpace(line) - line = strings.TrimLeft(line, unicode.ZeroWidthSpace) - - if line == target { - return true - } - } - - return false -} - -func contains(targets []string, line string) bool { - for _, target := range targets { - target = ansi.Strip(target) - if strings.Contains(line, target) { - return true - } - } - - return false -} - -func IsOnLineBeforeTargetEquals(targets []string, lines []string, i int) bool { - for _, target := range targets { - nextLine := lines[i+1] - nextLine = ansi.Strip(nextLine) - nextLine = strings.TrimSpace(nextLine) - nextLine = strings.TrimLeft(nextLine, unicode.ZeroWidthSpace) - - if nextLine == target { - return true - } - } - - return false -} - -func IsOnLineBeforeTargetContains(targets []string, lines []string, i int) bool { - for _, target := range targets { - nextLine := lines[i+1] - nextLine = ansi.Strip(nextLine) - nextLine = strings.TrimLeft(nextLine, " ") - - if strings.Contains(nextLine, target) { - return true - } - } - - return false -} diff --git a/markdown/postprocessor/postprocessor.go b/markdown/postprocessor/postprocessor.go @@ -1,71 +0,0 @@ -package postprocessor - -import ( - "strings" - - "git.figbert.com/clx-browser/constants/margins" - "git.figbert.com/clx-browser/constants/unicode" - - t "github.com/MichaelMure/go-term-text" - - terminal "github.com/wayneashleyberry/terminal-dimensions" -) - -const ( - newLine = "\n" -) - -func Process(text string, url string) string { - text = filterSite(text, url) - text = moveZeroWidthSpaceUpOneLine(text) - text = indent(text) - text = deIndentInfoSection(text) - - return text -} - -func moveZeroWidthSpaceUpOneLine(text string) string { - return strings.ReplaceAll(text, newLine+unicode.ZeroWidthSpace, - unicode.ZeroWidthSpace+newLine) -} - -func indent(commentSection string) string { - indentBlock := strings.Repeat(" ", margins.ReaderViewLeftMargin) - - width, err := terminal.Width() - if err != nil { - panic("Could not determine terminal width") - } - - indentedCommentSection, _ := t.WrapWithPad(commentSection, int(width), indentBlock) - - return indentedCommentSection -} - -func deIndentInfoSection(commentSection string) string { - var sb strings.Builder - - lines := strings.Split(commentSection, "\n") - - for i, line := range lines { - isOnLastLine := i == len(lines)-1 - isInfoSection := strings.Contains(line, "╭") || strings.Contains(line, "│") || - strings.Contains(line, "╰") - - if isInfoSection { - deIndentedLine := strings.TrimPrefix(line, " ") - - sb.WriteString(deIndentedLine + "\n") - - continue - } - - if isOnLastLine { - continue - } - - sb.WriteString(line + "\n") - } - - return sb.String() -} diff --git a/markdown/postprocessor/rules.go b/markdown/postprocessor/rules.go @@ -1,129 +0,0 @@ -package postprocessor - -import ( - "strings" - - "git.figbert.com/clx-browser/markdown/postprocessor/filter" -) - -func filterSite(text string, url string) string { - ruleSet := filter.RuleSet{} - - switch { - case strings.Contains(url, "en.wikipedia.org"): - text = strings.ReplaceAll(text, "[edit]", "") - text = removeWikipediaReferences(text) - - ruleSet.EndBeforeLineEquals("References") - ruleSet.EndBeforeLineEquals("Footnotes") - - return ruleSet.Filter(text) - - case strings.Contains(url, "bbc.com") || strings.Contains(url, "bbc.co.uk"): - return processBBC(text) - - case strings.Contains(url, "nytimes.com"): - ruleSet.SkipParContains("Credit…") - ruleSet.SkipParContains("This is a developing story. Check back for updates.") - - ruleSet.SkipLineEquals("Credit") - ruleSet.SkipLineEquals("Image") - - return ruleSet.Filter(text) - - case strings.Contains(url, "economist.com"): - ruleSet.SkipParContains("Listen to this story") - ruleSet.SkipParContains("Your browser does not support the ") - ruleSet.SkipParContains("Listen on the go") - ruleSet.SkipParContains("Get The Economist app and play articles") - ruleSet.SkipParContains("Play in app") - ruleSet.SkipParContains("Enjoy more audio and podcasts on iOS or Android") - - ruleSet.EndBeforeLineContains("This article appeared in the") - ruleSet.EndBeforeLineContains("For more coverage of ") - - return ruleSet.Filter(text) - - case strings.Contains(url, "tomshardware.com"): - ruleSet.SkipParContains("1. Home") - ruleSet.SkipParContains("2. News") - ruleSet.SkipParContains("(Image credit: ") - - return ruleSet.Filter(text) - - case strings.Contains(url, "cnn.com"): - ruleSet.SkipParContains("Credit: ") - - return ruleSet.Filter(text) - - case strings.Contains(url, "arstechnica.com"): - ruleSet.SkipParContains("Enlarge/ ") - ruleSet.SkipParContains("This story originally appeared on ") - - return ruleSet.Filter(text) - - case strings.Contains(url, "macrumors.com"): - ruleSet.EndBeforeLineEquals("Top Stories") - ruleSet.EndBeforeLineEquals("Related Stories") - - return ruleSet.Filter(text) - - case strings.Contains(url, "wired.com") || strings.Contains(url, "wired.co.uk"): - ruleSet.SkipParContains("Read more: ") - ruleSet.SkipParContains("Do you use social media regularly? Take our short survey.") - - ruleSet.EndBeforeLineEquals("More Great WIRED Stories") - - return ruleSet.Filter(text) - - case strings.Contains(url, "theguardian.com"): - ruleSet.SkipParContains("Photograph:") - - return ruleSet.Filter(text) - - case strings.Contains(url, "axios.com"): - ruleSet.SkipParContains("Sign up for our daily briefing") - ruleSet.SkipParContains("Catch up on the day's biggest business stories") - ruleSet.SkipParContains("Stay on top of the latest market trends") - ruleSet.SkipParContains("Sports news worthy of your time") - ruleSet.SkipParContains("Tech news worthy of your time") - ruleSet.SkipParContains("Get the inside stories") - ruleSet.SkipParContains("Axios on your phone") - ruleSet.SkipParContains("Catch up on coronavirus stories and special reports") - ruleSet.SkipParContains("Want a daily digest of the top ") - ruleSet.SkipParContains("Get a daily digest of the most important stories ") - ruleSet.SkipParContains("Download for free.") - ruleSet.SkipParContains("Sign up for free.") - ruleSet.SkipParContains("Make your busy days simpler with Axios AM/PM") - ruleSet.SkipParContains("Subscribe to Axios Closer") - ruleSet.SkipParContains("Get breaking news") - ruleSet.SkipParContains("Sign up for Axios") - ruleSet.SkipParContains("Stay up-to-date on the most important and interesting") - - return ruleSet.Filter(text) - - case strings.Contains(url, "9to5mac.com"): - ruleSet.SkipParContains("We use income earning auto affiliate links.") - ruleSet.SkipParContains("Check out 9to5Mac on YouTube for more Apple news:") - - ruleSet.EndBeforeLineEquals("About the Author") - - return ruleSet.Filter(text) - - case strings.Contains(url, "smithsonianmag.com"): - ruleSet.SkipParContains("smithsonianmag.com") - - ruleSet.EndBeforeLineEquals("Like this article?") - - return ruleSet.Filter(text) - - case strings.Contains(url, "cnet.com"): - ruleSet.SkipParContains("Read more:") - ruleSet.SkipParContains("Stay up-to-date on the latest news") - - return ruleSet.Filter(text) - - default: - return text - } -} diff --git a/markdown/postprocessor/wikipedia.go b/markdown/postprocessor/wikipedia.go @@ -1,17 +0,0 @@ -package postprocessor - -import ( - "strconv" - "strings" -) - -func removeWikipediaReferences(input string) string { - inputWithoutReferences := input - - for i := 1; i < 256; i++ { - number := strconv.Itoa(i) - inputWithoutReferences = strings.ReplaceAll(inputWithoutReferences, "["+number+"]", "") - } - - return inputWithoutReferences -} diff --git a/markdown/preprocessor/preprocessor.go b/markdown/preprocessor/preprocessor.go @@ -1,26 +0,0 @@ -package preprocessor - -import ( - "strings" - - "git.figbert.com/clx-browser/markdown" -) - -func ConvertItalicTags(text string) string { - text = strings.ReplaceAll(text, "<i>", markdown.ItalicStart) - text = strings.ReplaceAll(text, "</i>", markdown.ItalicStop) - text = strings.ReplaceAll(text, "<em>", markdown.ItalicStart) - text = strings.ReplaceAll(text, "</em>", markdown.ItalicStop) - - return text -} - -func ConvertBoldTags(text string) string { - text = strings.ReplaceAll(text, "<b>", markdown.BoldStart) - text = strings.ReplaceAll(text, "</b>", markdown.BoldStop) - - text = strings.ReplaceAll(text, "<strong>", markdown.BoldStart) - text = strings.ReplaceAll(text, "</strong>", markdown.BoldStop) - - return text -} diff --git a/markdown/renderer/renderer.go b/markdown/renderer/renderer.go @@ -1,495 +0,0 @@ -package renderer - -import ( - "regexp" - "strings" - - "git.figbert.com/clx-browser/constants/unicode" - "git.figbert.com/clx-browser/markdown" - "git.figbert.com/clx-browser/meta" - "git.figbert.com/clx-browser/syntax" - - "github.com/charmbracelet/glamour" - - terminal "github.com/wayneashleyberry/terminal-dimensions" - - termtext "github.com/MichaelMure/go-term-text" - . "github.com/logrusorgru/aurora/v3" -) - -const ( - indentLevel1 = " " - indentLevel2 = indentLevel1 + indentLevel1 - indentLevel3 = indentLevel2 + indentLevel1 - - codeStart = "[CLX_CODE_START]" - codeEnd = "[CLX_CODE_END]" -) - -func CreateHeader(title string, domain string, lineWidth int) string { - return meta.GetReaderModeMetaBlock(title, domain, lineWidth) -} - -func ToString(blocks []*markdown.Block, lineWidth int, indentBlock string) string { - output := "" - - for _, block := range blocks { - switch block.Kind { - case markdown.Text: - output += renderText(block.Text, lineWidth) + "\n\n" - - case markdown.Image: - output += renderImage(block.Text, lineWidth) + "\n\n" - - case markdown.Code: - output += renderCode(block.Text) + "\n\n" - - case markdown.Quote: - output += renderQuote(block.Text, lineWidth, indentBlock) + "\n\n" - - case markdown.Table: - output += renderTable(block.Text) + "\n\n" - - case markdown.List: - output += renderList(block.Text, lineWidth) + "\n\n" - - case markdown.Divider: - output += renderDivider(lineWidth) + "\n\n" - - case markdown.H1: - output += h1(block.Text, lineWidth) + "\n\n" - - case markdown.H2: - output += h2(block.Text, lineWidth) + "\n\n" - - case markdown.H3: - output += h3(block.Text, lineWidth) + "\n\n" - - case markdown.H4: - output += h4(block.Text, lineWidth) + "\n\n" - - case markdown.H5: - output += h5(block.Text, lineWidth) + "\n\n" - - case markdown.H6: - output += h6(block.Text, lineWidth) + "\n\n" - - default: - output += renderText(block.Text, lineWidth) + "\n\n" - } - } - - output = strings.TrimLeft(output, "\n") - - return output -} - -func renderDivider(lineWidth int) string { - divider := strings.Repeat("-", lineWidth-len(indentLevel1)*2) - - return Faint(indentLevel1 + divider).String() -} - -func renderText(text string, lineWidth int) string { - text = it(text) - text = bld(text) - text = removeHrefs(text) - text = unescapeCharacters(text) - text = removeImageReference(text) - - text = syntax.RemoveUnwantedNewLines(text) - text = highlightBackticks(text) - text = syntax.HighlightMentions(text) - text = syntax.TrimURLs(text, true) - - text, _ = termtext.Wrap(text, lineWidth) - - return text -} - -func renderList(text string, lineWidth int) string { - // Remove unwanted newlines - exp := regexp.MustCompile(`([\w\W[:cntrl:]])(\n)\s*([a-zA-Z\x60(])`) - text = exp.ReplaceAllString(text, `$1 $3`) - - text = it(text) - text = bld(text) - text = removeImageReference(text) - text = removeHrefs(text) - text = unescapeCharacters(text) - text = highlightBackticks(text) - - output := "" - lines := strings.Split(text, "\n") - - for _, line := range lines { - exp := regexp.MustCompile(`^\s*(-|\d+\.)`) - - listToken := exp.FindString(line) - listText := strings.TrimLeft(line, listToken) - - paddingBuffer := strings.Repeat(" ", len(listToken)) - padding := indentLevel1 + paddingBuffer + " " - - wrappedIndentedItem, _ := termtext.WrapWithPadIndent(listToken+listText, lineWidth, indentLevel1, padding) - wrappedIndentedItem = insertSpaceAfterItemListSeparator(wrappedIndentedItem) - - output += wrappedIndentedItem + "\n" - } - - output = replaceListPrefixes(output) - output = trimLeadingZero(output) - - return strings.TrimRight(output, "\n") -} - -func renderImage(text string, lineWidth int) string { - red := "\u001B[31m" - italic := "\u001B[3m" - faint := "\u001B[2m" - normal := "\u001B[0m" - imageLabel := normal + red + faint + "Image " + normal + faint + italic - - text = regexp.MustCompile(`!\[(.*?)\]\(.*?\)$`). - ReplaceAllString(text, imageLabel+`$1`) - - text = regexp.MustCompile(`!\[(.*?)\]\(.*?\)\s`). - ReplaceAllString(text, imageLabel+`$1`) - - text = regexp.MustCompile(`!\[(.*?)\]\(.*?\)`). - ReplaceAllString(text, imageLabel+`$1`) - - if text == imageLabel { - return indentLevel2 + text + normal - } - - lines := strings.Split(text, imageLabel) - output := "" - - for _, line := range lines { - if len(lines) == 1 || len(lines) == 0 { - output += imageLabel + line + "\n\n" - - break - } - - if line == "" { - continue - } - - output += imageLabel + line + "\n\n" - } - - output = strings.TrimSuffix(output, "\n\n") - output += normal - - output = it(output) - output = bld(output) - output = removeDoubleWhitespace(output) - - padding := termtext.WrapPad(indentLevel1) - output, _ = termtext.Wrap(output, lineWidth, padding) - - return output -} - -func renderCode(text string) string { - screenWidth, _ := terminal.Width() - - text = strings.TrimSuffix(text, "\n") - text = strings.TrimPrefix(text, "\n") - - text = Faint(text).String() - text = removeHrefs(text) - - padding := termtext.WrapPad(indentLevel1) - text, _ = termtext.Wrap(text, int(screenWidth), padding) - - return text -} - -func renderQuote(text string, lineWidth int, indentSymbol string) string { - text = Italic(text).Faint().String() - text = unescapeCharacters(text) - text = removeHrefs(text) - text = removeUnwantedNewLines(text) - - indentBlock := " " + indentSymbol - text = itReversed(text) - text = bldInQuote(text) - - padding := termtext.WrapPad(indentLevel1 + Faint(indentBlock).String()) - text, _ = termtext.Wrap(text, lineWidth, padding) - - return text -} - -func removeUnwantedNewLines(text string) string { - paragraphSeparator := "\n\n" - paragraphs := strings.Split(text, paragraphSeparator) - output := "" - - for _, paragraph := range paragraphs { - paragraph = syntax.RemoveUnwantedNewLines(paragraph) - - output += paragraph + paragraphSeparator - } - - output = strings.TrimSuffix(output, paragraphSeparator) - - return output -} - -func renderTable(text string) string { - screenWidth, _ := terminal.Width() - text = strings.ReplaceAll(text, markdown.ItalicStart, "") - text = strings.ReplaceAll(text, markdown.ItalicStop, "") - - text = strings.ReplaceAll(text, markdown.BoldStart, "") - text = strings.ReplaceAll(text, markdown.BoldStop, "") - - text = unescapeCharacters(text) - text = removeImageReference(text) - - r, _ := glamour.NewTermRenderer(glamour.WithStyles(glamour.NoTTYStyleConfig), - glamour.WithWordWrap(int(screenWidth))) - - out, _ := r.Render(text) - - out = strings.ReplaceAll(out, " --- ", " ") - out = strings.TrimPrefix(out, "\n") - out = strings.TrimLeft(out, " ") - out = strings.TrimPrefix(out, "\n") - out = strings.TrimSuffix(out, "\n\n") - - return out -} - -func removeImageReference(text string) string { - exp := regexp.MustCompile(`!\[(.*?)\]\(.*?\)`) - - return exp.ReplaceAllString(text, `$1`) -} - -func it(text string) string { - italic := "\u001B[3m" - noItalic := "\u001B[23m" - - text = strings.ReplaceAll(text, markdown.ItalicStart, italic) - text = strings.ReplaceAll(text, markdown.ItalicStop, noItalic) - - return text -} - -func itReversed(text string) string { - italic := "\u001B[3m" - noItalic := "\u001B[23m" - - text = strings.ReplaceAll(text, markdown.ItalicStart, noItalic) - text = strings.ReplaceAll(text, markdown.ItalicStop, italic) - - return text -} - -func bld(text string) string { - // bold := "\033[31m" - // noBold := "\033[0m" - - text = strings.ReplaceAll(text, markdown.BoldStart, "") - text = strings.ReplaceAll(text, markdown.BoldStop, "") - - return text -} - -func bldInQuote(text string) string { - // bold := "\033[31m" - // noBold := "\033[0m" - - text = strings.ReplaceAll(text, markdown.BoldStart, "") - text = strings.ReplaceAll(text, markdown.BoldStop, "") - - return text -} - -func h1(text string, lineWidth int) string { - text = preFormatHeader(text) - text = Bold(text).String() - - text, _ = termtext.Wrap(text, lineWidth) - - return unicode.ZeroWidthSpace + text -} - -func h2(text string, lineWidth int) string { - text = preFormatHeader(text) - text = Bold(text).String() - - text, _ = termtext.Wrap(text, lineWidth) - - return unicode.ZeroWidthSpace + text -} - -func h3(text string, lineWidth int) string { - text = preFormatHeader(text) - text = Bold(text).Underline().Blue().String() - - text, _ = termtext.Wrap(text, lineWidth) - - return unicode.ZeroWidthSpace + text -} - -func h4(text string, lineWidth int) string { - text = preFormatHeader(text) - text = Bold(text).Underline().Yellow().String() - - text, _ = termtext.WrapWithPad(text, lineWidth, indentLevel1) - - return unicode.ZeroWidthSpace + text -} - -func h5(text string, lineWidth int) string { - text = preFormatHeader(text) - text = Bold(text).Underline().Green().String() - - text, _ = termtext.WrapWithPad(text, lineWidth, indentLevel2) - - return unicode.ZeroWidthSpace + text -} - -func h6(text string, lineWidth int) string { - text = preFormatHeader(text) - text = Bold(text).Underline().Cyan().String() - - text, _ = termtext.WrapWithPad(text, lineWidth, indentLevel3) - - return unicode.ZeroWidthSpace + text -} - -func removeHrefs(text string) string { - exp := regexp.MustCompile(`<a href=.+>(.+)</a>`) - text = exp.ReplaceAllString(text, `$1`) - - return text -} - -func insertSpaceAfterItemListSeparator(text string) string { - exp := regexp.MustCompile(`(^\s*-)(\S)`) - - return exp.ReplaceAllString(text, `$1 $2`) -} - -func preFormatHeader(text string) string { - text = removeImageReference(text) - text = strings.TrimLeft(text, "# ") - text = removeBoldAndItalicTags(text) - text = unescapeCharacters(text) - text = it(text) - - return text -} - -func unescapeCharacters(text string) string { - text = strings.ReplaceAll(text, `\|`, "|") - text = strings.ReplaceAll(text, `\-`, "-") - text = strings.ReplaceAll(text, `\_`, "_") - text = strings.ReplaceAll(text, `\*`, "*") - text = strings.ReplaceAll(text, `\\`, `\`) - text = strings.ReplaceAll(text, `\#`, "#") - text = strings.ReplaceAll(text, `\.`, ".") - text = strings.ReplaceAll(text, `\>`, ">") - text = strings.ReplaceAll(text, `\<`, "<") - text = strings.ReplaceAll(text, "\\`", "`") - text = strings.ReplaceAll(text, "...", "…") - text = strings.ReplaceAll(text, `\(`, "(") - - return text -} - -func removeDoubleWhitespace(text string) string { - text = strings.ReplaceAll(text, "  ", " ") - - return text -} - -func removeBoldAndItalicTags(text string) string { - text = strings.ReplaceAll(text, markdown.BoldStart, "") - text = strings.ReplaceAll(text, markdown.BoldStop, "") - - text = strings.ReplaceAll(text, markdown.ItalicStart, "") - text = strings.ReplaceAll(text, markdown.ItalicStop, "") - - return text -} - -func trimLeadingZero(text string) string { - text = strings.ReplaceAll(text, indentLevel2+"01", indentLevel2+" 1") - text = strings.ReplaceAll(text, indentLevel2+"02", indentLevel2+" 2") - text = strings.ReplaceAll(text, indentLevel2+"03", indentLevel2+" 3") - text = strings.ReplaceAll(text, indentLevel2+"04", indentLevel2+" 4") - text = strings.ReplaceAll(text, indentLevel2+"05", indentLevel2+" 5") - text = strings.ReplaceAll(text, indentLevel2+"06", indentLevel2+" 6") - text = strings.ReplaceAll(text, indentLevel2+"07", indentLevel2+" 7") - text = strings.ReplaceAll(text, indentLevel2+"08", indentLevel2+" 8") - text = strings.ReplaceAll(text, indentLevel2+"09", indentLevel2+" 9") - - return text -} - -func highlightBackticks(text string) string { - magenta := "\u001B[35m" - italic := "\u001B[3m" - normal := "\u001B[0m" - - backtick := "`" - numberOfBackticks := strings.Count(text, backtick) - numberOfBackticksIsOdd := numberOfBackticks%2 != 0 - - if numberOfBackticks == 0 || numberOfBackticksIsOdd { - return text - } - - isOnFirstBacktick := true - - for i := 0; i < numberOfBackticks+1; i++ { - if isOnFirstBacktick { - text = strings.Replace(text, backtick, codeStart, 1) - } else { - text = strings.Replace(text, backtick, codeEnd, 1) - } - - isOnFirstBacktick = !isOnFirstBacktick - } - - exp := regexp.MustCompile(`([\S])(\[CLX_CODE_START\])`) - text = exp.ReplaceAllString(text, `$1 $2`) - - text = strings.ReplaceAll(text, "( "+codeStart, "("+codeStart) - - text = strings.ReplaceAll(text, codeStart, normal+magenta+italic) - text = strings.ReplaceAll(text, codeEnd, normal) - - return text -} - -func replaceListPrefixes(text string) string { - lines := strings.Split(text, "\n") - output := "" - - for _, line := range lines { - line = regexp.MustCompile(`^`+strings.Repeat(indentLevel1, 2)+"-"). - ReplaceAllString(line, strings.Repeat(indentLevel1, 2)+"•") - - line = regexp.MustCompile(`^`+strings.Repeat(indentLevel1, 3)+"-"). - ReplaceAllString(line, strings.Repeat(indentLevel1, 3)+"◦") - - line = regexp.MustCompile(`^`+strings.Repeat(indentLevel1, 4)+"-"). - ReplaceAllString(line, strings.Repeat(indentLevel1, 4)+"▪") - - line = regexp.MustCompile(`^`+strings.Repeat(indentLevel1, 5)+"-"). - ReplaceAllString(line, strings.Repeat(indentLevel1, 5)+"▫") - - output += line + "\n" - } - - return output -} diff --git a/meta/meta.go b/meta/meta.go @@ -1,31 +0,0 @@ -package meta - -import ( - "git.figbert.com/clx-browser/constants/unicode" - - text "github.com/MichaelMure/go-term-text" - - . "github.com/logrusorgru/aurora/v3" - - "github.com/charmbracelet/lipgloss" -) - -const ( - newLine = "\n" - newParagraph = "\n\n" -) - -func GetReaderModeMetaBlock(title string, url string, lineWidth int) string { - style := lipgloss.NewStyle(). - BorderStyle(lipgloss.RoundedBorder()). - PaddingLeft(1). - PaddingRight(1). - Width(lineWidth) - - formattedTitle, _ := text.Wrap(Bold(title).String(), lineWidth) - formattedTitle = unicode.ZeroWidthSpace + newLine + formattedTitle - formattedURL := Blue(text.TruncateMax(url, lineWidth-2)).String() - info := newParagraph + Green("Reader Mode").String() - - return formattedTitle + newParagraph + style.Render(formattedURL+info) + newParagraph -} diff --git a/reader/reader.go b/reader/reader.go @@ -5,16 +5,10 @@ import ( "log" "net/http" "net/url" - "strings" "time" - "git.figbert.com/clx-browser/markdown" - "git.figbert.com/clx-browser/markdown/preprocessor" - "github.com/JohannesKaufmann/html-to-markdown/plugin" - "github.com/PuerkitoBio/goquery" - md "github.com/JohannesKaufmann/html-to-markdown" "github.com/go-shiori/go-readability" @@ -26,61 +20,14 @@ func GetNew(url string) (string, string, error) { return "", "", fmt.Errorf("could not fetch url: %w", httpErr) } - href := md.Rule{ - Filter: []string{"a"}, - Replacement: func(content string, selec *goquery.Selection, opt *md.Options) *string { - // If the span element has not the classname `bb_strike` return nil. - // That way the next rules will apply. In this case the commonmark rules. - // -> return nil -> next rule applies - //if !selec.HasClass("href") { - // return nil - //} - - // Trim spaces so that the following does NOT happen: `~ and cake~`. - // Because of the space it is not recognized as strikethrough. - // -> trim spaces at begin&end of string when inside strong/italic/... - content = strings.TrimSpace(content) - // return md.String("[" + content + "]") - return md.String(content) - }, - } - - italic := md.Rule{ - Filter: []string{"i"}, - Replacement: func(content string, selec *goquery.Selection, opt *md.Options) *string { - // If the span element has not the classname `bb_strike` return nil. - // That way the next rules will apply. In this case the commonmark rules. - // -> return nil -> next rule applies - //if !selec.HasClass("href") { - // return nil - //} - - // Trim spaces so that the following does NOT happen: `~ and cake~`. - // Because of the space it is not recognized as strikethrough. - // -> trim spaces at begin&end of string when inside strong/italic/... - content = strings.TrimSpace(content) - return md.String(markdown.ItalicStart + content + markdown.ItalicStop) - }, - } - opt := &md.Options{} - converter := md.NewConverter("", true, opt) - converter.AddRules(href) - converter.AddRules(italic) + converter := md.NewConverter(url, true, opt) converter.Use(plugin.Table()) - // converter.AddRules(span) - - art.Content = preprocessor.ConvertItalicTags(art.Content) - art.Content = preprocessor.ConvertBoldTags(art.Content) markdown, err := converter.ConvertString(art.Content) if err != nil { log.Fatal(err) } - // fmt.Println("md ->", markdown) - - markdown = strings.ReplaceAll(markdown, "<span>", "") - markdown = strings.ReplaceAll(markdown, "</span>", "") return art.Title, markdown, nil } diff --git a/strip-ansi/strip-ansi.go b/strip-ansi/strip-ansi.go @@ -1,14 +0,0 @@ -package stripansi - -import ( - "regexp" -) - -const ansi = "[\u001B\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\u0007)|" + - "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))" - -func Strip(text string) string { - expression := regexp.MustCompile(ansi) - - return expression.ReplaceAllString(text, "") -} diff --git a/syntax/syntax.go b/syntax/syntax.go @@ -1,45 +0,0 @@ -package syntax - -import ( - "regexp" - "strings" - - "github.com/logrusorgru/aurora/v3" -) - -const reset = "\033[0m" - -func RemoveUnwantedNewLines(text string) string { - exp := regexp.MustCompile(`([\w\W[:cntrl:]])(\n)([a-zA-Z0-9" \-<[:cntrl:]…])`) - - return exp.ReplaceAllString(text, `$1`+" "+`$3`) -} - -func TrimURLs(comment string, highlightComment bool) string { - expression := regexp.MustCompile(`<a href=".*?" rel="nofollow">`) - - if !highlightComment { - return expression.ReplaceAllString(comment, "") - } - - comment = expression.ReplaceAllString(comment, "") - - e := regexp.MustCompile(`https?://([^,"\) \n]+)`) - comment = e.ReplaceAllString(comment, aurora.Blue(`$1`).String()) - - comment = strings.ReplaceAll(comment, "."+reset+" ", reset+". ") - - return comment -} - -func HighlightMentions(input string) string { - exp := regexp.MustCompile(`((?:^| )\B@[\w.]+)`) - input = exp.ReplaceAllString(input, aurora.Yellow(`$1`).String()) - - input = strings.ReplaceAll(input, aurora.Yellow("@dang").String(), - aurora.Green("@dang").String()) - input = strings.ReplaceAll(input, aurora.Yellow(" @dang").String(), - aurora.Green(" @dang").String()) - - return input -}