@@ -14,6 +14,7 @@ import (
1414 "strings"
1515 "time"
1616
17+ "github.com/alecthomas/chroma/v2"
1718 "github.com/alecthomas/chroma/v2/formatters"
1819 "github.com/alecthomas/chroma/v2/lexers"
1920 "github.com/alecthomas/chroma/v2/styles"
@@ -236,6 +237,37 @@ type StackOverflowResult struct {
236237 QuotaRemaining int `json:"quota_remaining"`
237238}
238239
240+ type StackOverflowQuestion struct {
241+ Items []struct {
242+ Tags []string `json:"tags"`
243+ Owner struct {
244+ AccountID int `json:"account_id"`
245+ Reputation int `json:"reputation"`
246+ UserID int `json:"user_id"`
247+ UserType string `json:"user_type"`
248+ ProfileImage string `json:"profile_image"`
249+ DisplayName string `json:"display_name"`
250+ Link string `json:"link"`
251+ } `json:"owner"`
252+ IsAnswered bool `json:"is_answered"`
253+ ViewCount int `json:"view_count"`
254+ ProtectedDate int `json:"protected_date"`
255+ AnswerCount int `json:"answer_count"`
256+ Score int `json:"score"`
257+ LastActivityDate int `json:"last_activity_date"`
258+ CreationDate int `json:"creation_date"`
259+ LastEditDate int `json:"last_edit_date,omitempty"`
260+ QuestionID int `json:"question_id"`
261+ ContentLicense string `json:"content_license"`
262+ Link string `json:"link"`
263+ Title string `json:"title"`
264+ Body string `json:"body"`
265+ } `json:"items"`
266+ HasMore bool `json:"has_more"`
267+ QuotaMax int `json:"quota_max"`
268+ QuotaRemaining int `json:"quota_remaining"`
269+ }
270+
239271type OpenSerpResult struct {
240272 Rank int `json:"rank"`
241273 URL string `json:"url"`
@@ -251,6 +283,7 @@ type Config struct {
251283 Style string
252284 Lexer string
253285 QuestionNum int
286+ ShowQuestion bool
254287 AnswerNum int
255288 OpenSerpHost string
256289 OpenSerpPort int
@@ -297,6 +330,7 @@ type Result struct {
297330 QuestionId int
298331 UpvoteCount int
299332 Date time.Time
333+ Body string
300334 Answers []* Answer
301335}
302336
@@ -419,6 +453,7 @@ func FetchStackOverflow(conf *Config, results map[int]*Result) error {
419453 }
420454 url := fmt .Sprintf ("https://api.stackexchange.com/2.3/questions/%s/answers?order=desc&sort=votes&site=stackoverflow&filter=withbody" ,
421455 netUrl .QueryEscape (strings .Join (questions , ";" )))
456+ //https://api.stackexchange.com/2.2/questions/6827752;48553152/?order=desc&sort=activity&site=stackoverflow&filter=withbody
422457 req , err := http .NewRequest (http .MethodGet , url , nil )
423458 if err != nil {
424459 return err
@@ -436,11 +471,37 @@ func FetchStackOverflow(conf *Config, results map[int]*Result) error {
436471 if err != nil {
437472 return err
438473 }
474+ soQuestions := make (map [int ]string )
475+ if conf .ShowQuestion {
476+ url = fmt .Sprintf ("https://api.stackexchange.com/2.3/questions/%s/?order=desc&sort=activity&site=stackoverflow&filter=withbody" ,
477+ netUrl .QueryEscape (strings .Join (questions , ";" )))
478+ req , err := http .NewRequest (http .MethodGet , url , nil )
479+ if err != nil {
480+ return err
481+ }
482+ res , err := conf .Client .Do (req )
483+ if err != nil {
484+ return err
485+ }
486+ defer res .Body .Close ()
487+ if res .StatusCode > 299 {
488+ return fmt .Errorf ("failed connecting to Stack Overflow API: %s" , res .Status )
489+ }
490+ var soQuestionsResp StackOverflowQuestion
491+ err = json .NewDecoder (res .Body ).Decode (& soQuestionsResp )
492+ if err != nil {
493+ return err
494+ }
495+ for _ , q := range soQuestionsResp .Items {
496+ soQuestions [q .QuestionID ] = q .Body
497+ }
498+ }
439499 for _ , item := range soResp .Items {
440500 result , ok := results [item .QuestionID ]
441501 if ! ok {
442502 continue
443503 }
504+ result .Body = soQuestions [item .QuestionID ]
444505 result .Answers = append (result .Answers ,
445506 & Answer {
446507 Title : result .Title ,
@@ -455,6 +516,35 @@ func FetchStackOverflow(conf *Config, results map[int]*Result) error {
455516 return nil
456517}
457518
519+ func highlightText (text string , sb * strings.Builder , formatter chroma.Formatter , lexer chroma.Lexer , style * chroma.Style ) error {
520+ t := prepareText (text )
521+ codeStartIdx = strings .Index (t , codeStartTag )
522+ if codeStartIdx == - 1 {
523+ sb .WriteString (fmtText (t ))
524+ }
525+ for codeStartIdx != - 1 {
526+ codeEndIdx = strings .Index (t , codeEndTag )
527+ if codeEndIdx == - 1 {
528+ break
529+ }
530+ sb .WriteString (fmtText (t [:codeStartIdx ]))
531+ iterator , err := lexer .Tokenise (nil , html .UnescapeString (t [codeStartIdx + len (codeStartTag ):codeEndIdx ]))
532+ if err != nil {
533+ return err
534+ }
535+ err = formatter .Format (sb , style , iterator )
536+ if err != nil {
537+ return err
538+ }
539+ t = t [codeEndIdx + len (codeEndTag ):]
540+ codeStartIdx = strings .Index (t , codeStartTag )
541+ if codeStartIdx == - 1 {
542+ sb .WriteString (fmtText (t ))
543+ }
544+ }
545+ return nil
546+ }
547+
458548func GetAnswers (conf * Config ,
459549 fetchResults func (* Config , map [int ]* Result ) error ,
460550 fetchAnswers func (* Config , map [int ]* Result ) error ,
@@ -506,37 +596,25 @@ func GetAnswers(conf *Config,
506596 return cmp .Compare (a .Score , b .Score )
507597 })
508598 answers .WriteString (res .String ())
599+ if conf .ShowQuestion {
600+ var question strings.Builder
601+ err = highlightText (res .Body , & question , formatter , lexer , style )
602+ if err != nil {
603+ return "" , err
604+ }
605+ answers .WriteString ("\n \n " )
606+ answers .WriteString (question .String ())
607+ }
509608 var aIdx int
510609 for _ , ans := range slices .Backward (res .Answers ) {
511610 if aIdx >= conf .AnswerNum {
512611 break
513612 }
514613 aIdx ++
515614 answers .WriteString (ans .String ())
516- t := prepareText (ans .Body )
517- codeStartIdx = strings .Index (t , codeStartTag )
518- if codeStartIdx == - 1 {
519- answers .WriteString (fmtText (t ))
520- }
521- for codeStartIdx != - 1 {
522- codeEndIdx = strings .Index (t , codeEndTag )
523- if codeEndIdx == - 1 {
524- break
525- }
526- answers .WriteString (fmtText (t [:codeStartIdx ]))
527- iterator , err := lexer .Tokenise (nil , html .UnescapeString (t [codeStartIdx + len (codeStartTag ):codeEndIdx ]))
528- if err != nil {
529- return "" , err
530- }
531- err = formatter .Format (& answers , style , iterator )
532- if err != nil {
533- return "" , err
534- }
535- t = t [codeEndIdx + len (codeEndTag ):]
536- codeStartIdx = strings .Index (t , codeStartTag )
537- if codeStartIdx == - 1 {
538- answers .WriteString (fmtText (t ))
539- }
615+ err = highlightText (ans .Body , & answers , formatter , lexer , style )
616+ if err != nil {
617+ return "" , err
540618 }
541619 }
542620 }
0 commit comments