diff --git a/parser.go b/parser.go index 4ce96228..826bd075 100644 --- a/parser.go +++ b/parser.go @@ -1,11 +1,13 @@ package main import ( + "bytes" "fmt" "io" "os" "strconv" "strings" + "html" ) // A basic set implementation for strings. @@ -673,3 +675,66 @@ func parseNumberMenu(input string) (intRanges, intRanges, stringSet, stringSet) return include, exclude, otherInclude, otherExclude } + +// Crude html parsing, good enough for the arch news +// This is only displayed in the terminal so there should be no security +// concerns +func parseNews(str string) string { + var buffer bytes.Buffer + var tagBuffer bytes.Buffer + var escapeBuffer bytes.Buffer + inTag := false + inEscape := false + + for _, char := range str { + if inTag { + if char == '>' { + inTag = false + switch tagBuffer.String() { + case "code": + buffer.WriteString(cyanCode) + case "/code": + buffer.WriteString(resetCode) + case "/p": + buffer.WriteRune('\n') + } + + continue + } + + tagBuffer.WriteRune(char) + continue + } + + if inEscape { + if char == ';' { + inEscape = false + escapeBuffer.WriteRune(char) + s := html.UnescapeString(escapeBuffer.String()) + buffer.WriteString(s) + continue + } + + escapeBuffer.WriteRune(char) + continue + } + + if char == '<' { + inTag = true + tagBuffer.Reset() + continue + } + + if char == '&' { + inEscape = true + escapeBuffer.Reset() + escapeBuffer.WriteRune(char) + continue + } + + buffer.WriteRune(char) + } + + buffer.WriteString(resetCode) + return buffer.String() +} diff --git a/print.go b/print.go index 582eec18..27416f97 100644 --- a/print.go +++ b/print.go @@ -417,21 +417,45 @@ outer: return nil } +type Item struct { + Title string `xml:"title"` + Link string `xml:"link"` + Description string `xml:"description"` + PubDate string `xml:"pubDate"` + Creator string `xml:"dc:creator"` +} + +func (item Item) Print() error { + date, err := time.Parse(time.RFC1123Z, item.PubDate) + + if err != nil { + return err + } + + fd := formatTime(int(date.Unix())) + + fmt.Println(bold(magenta(fd)), bold(strings.TrimSpace(item.Title))) + //fmt.Println(strings.TrimSpace(item.Link)) + + if !cmdArgs.existsArg("q", "quiet") { + desc := strings.TrimSpace(parseNews(item.Description)) + fmt.Println(desc) + } + + return nil +} + +type Channel struct { + Title string `xml:"title"` + Link string `xml:"link"` + Description string `xml:"description"` + Language string `xml:"language"` + Lastbuilddate string `xml:"lastbuilddate"` + Items []Item `xml:"item"` +} + type rss struct { - Channel struct { - Title string `xml:"title"` - Link string `xml:"link"` - Description string `xml:"description"` - Language string `xml:"language"` - Lastbuilddate string `xml:"lastbuilddate"` - Item []struct { - Title string `xml:"title"` - Link string `xml:"link"` - Description string `xml:"description"` - PubDate string `xml:"pubDate"` - Creator string `xml:"dc:creator"` - } `xml:"item"` - } `xml:"channel"` + Channel Channel `xml:"channel"` } func printNewsFeed() error { @@ -454,16 +478,20 @@ func printNewsFeed() error { return err } - for _, item := range rss.Channel.Item { - date, err := time.Parse(time.RFC1123Z, item.PubDate) - - if err != nil { - return err + if config.SortMode == BottomUp { + for i := len(rss.Channel.Items) - 1; i >= 0; i-- { + err := rss.Channel.Items[i].Print() + if err != nil { + return err + } + } + } else { + for i := 0; i < len(rss.Channel.Items); i++ { + err := rss.Channel.Items[i].Print() + if err != nil { + return err + } } - - fd := formatTime(int(date.Unix())) - - fmt.Println(magenta(fd), strings.TrimSpace(item.Title)) } return nil