1111import webbrowser
1212from pygments import highlight
1313from pygments .lexers .markup import MarkdownLexer
14- from pygments .formatters import Terminal256Formatter
14+ from pygments .lexers .html import HtmlLexer
15+ from pygments .formatters import TerminalFormatter
1516
1617from .error import SearchError
1718from .save import SaveSearchResults
3536
3637console = Console ()
3738
38- class Questions_Panel_stackoverflow ():
39+ class QuestionsPanel_stackoverflow ():
3940 def __init__ (self ):
40- self .questions_data = [] # list( list( question_title, question_link, question_id )... )
41+ self .questions_data = [] # list( list( question_title, question_id, question_link )... )
4142 self .answer_data = defaultdict (lambda : False ) # dict( question_id:list( body, link )) corresponding to self.questions_data
42- self .batch_ques_id = ""
4343 self .line_color = "bold red"
4444 self .heading_color = "bold blue"
45- self .search_content_url = "https://api.stackexchange.com/"
45+ self .utility = Utility ()
4646
4747 def populate_question_data (self , questions_list ):
48- """ Function to populate question data property
49- Creates batch_id request to stackexchange API and
50- Stores the returned data data in the following format:
51- list( list( question_title, question_link, question_id ) )
5248 """
53- for question_id in questions_list :
54- self .batch_ques_id += str (question_id ) + ";"
55- try :
56- resp = requests .get (
57- f"{ self .search_content_url } /2.2/questions/{ self .batch_ques_id [:- 1 ]} ?order=desc&sort=votes&site=stackoverflow&filter=!--1nZwsgqvRX"
58- )
59- except :
60- SearchError ("Search Failed" , "Try connecting to the internet" )
61- sys .exit ()
49+ Function to populate question data property
50+ Creates batch request to stackexchange API and to get question details of
51+ questions with id in the list. Stores the returned data data in the following format:
52+ list( list( question_title, question_link, question_id ) )
53+ """
54+ with console .status ("Getting the questions..." ):
55+ try :
56+ resp = requests .get (
57+ self .utility .get_batch_ques_url (questions_list )
58+ )
59+ except :
60+ SearchError ("Search Failed" , "Try connecting to the internet" )
61+ sys .exit ()
6262 json_ques_data = resp .json ()
6363 self .questions_data = [[item ['title' ], item ['question_id' ], item ['link' ]] for item in json_ques_data ["items" ]]
6464
65- def populate_answer_data (self ):
66- """ Function to populate answer data property
67- Creates batch_id request to stackexchange API and
68- Stores the returned data data in the following format:
69- list( list( question_title, question_link, question_id ) )
65+ def populate_answer_data (self , questions_list ):
7066 """
71- try :
72- resp = requests .get (
73- f"{ self .search_content_url } /2.2/questions/{ self .batch_ques_id [:- 1 ]} /answers?order=desc&sort=votes&site=stackoverflow&filter=!--1nZwsgqvRX"
74- )
75- except :
76- SearchError ("Search Failed" , "Try connecting to the internet" )
77- sys .exit ()
78- json_ans_data = resp .json ()
79- for item in json_ans_data ["items" ]:
80- self .answer_data [item ['question_id' ]] = item ['body_markdown' ]
81-
82- def return_formatted_ans (self , id ):
67+ Function to populate answer data property
68+ Creates batch request to stackexchange API to get ans of questions with
69+ question id in the list. Stores the returned data data in the following format:
70+ dict( question_id:list( body, link ) )
71+ """
72+ with console .status ("Searching answers..." ):
73+ try :
74+ resp = requests .get (
75+ self .utility .get_batch_ans_url (questions_list )
76+ )
77+ except :
78+ SearchError ("Search Failed" , "Try connecting to the internet" )
79+ sys .exit ()
80+ json_ans_data = resp .json ()
81+ for item in json_ans_data ["items" ]:
82+ if not (self .answer_data [item ['question_id' ]]):
83+ self .answer_data [item ['question_id' ]] = item ['body_markdown' ]
84+
85+ # Sometimes the StackExchange API fails to deliver some answers. The below code is to fetch them
86+ failed_ques_id = [question [1 ] for question in self .questions_data if not (self .answer_data [question [1 ]])]
87+ if not (len (failed_ques_id ) == 0 ):
88+ self .populate_answer_data (failed_ques_id )
89+
90+ def return_formatted_ans (self , ques_id ):
8391 # This function uses pygments lexers ad formatters to format the content in the preview screen
84- body_markdown = self .answer_data [int (id )]
92+ body_markdown = self .answer_data [int (ques_id )]
8593 if (body_markdown ):
8694 body_markdown = str (body_markdown )
87- body_markdown = body_markdown .replace ("&" , "&" )
88- body_markdown = body_markdown .replace ("<" , "<" )
89- body_markdown = body_markdown .replace (">" , ">" )
90- body_markdown = body_markdown .replace (""" , "\" " )
91- body_markdown = body_markdown .replace ("'" , "\' " )
92- body_markdown = body_markdown .replace ("'" , "\' " )
95+ xml_markup_replacement = [("&" , "&" ), ("<" , "<" ), (">" , ">" ), (""" , "\" " ), ("'" , "\' " ), ("'" , "\' " )]
96+ for convert_from , convert_to in xml_markup_replacement :
97+ body_markdown = body_markdown .replace (convert_from , convert_to )
9398 lexer = MarkdownLexer ()
94- formatter = Terminal256Formatter ( bg = "light" )
99+ formatter = TerminalFormatter ( )
95100 highlighted = highlight (body_markdown , lexer , formatter )
96101 else :
97102 highlighted = "Answer not viewable. Press enter to open in a browser"
@@ -103,18 +108,22 @@ def navigate_questions_panel(self):
103108 console .print ("[yellow] Use arrow keys to navigate. 'q' or 'Esc' to quit. 'Enter' to open in a browser" )
104109 console .print ()
105110 options = ["|" .join (map (str , question )) for question in self .questions_data ]
106- question_menu = TerminalMenu (options , preview_command = self .return_formatted_ans )
111+ question_menu = TerminalMenu (options , preview_command = self .return_formatted_ans , preview_size = 0.75 , )
107112 quitting = False
108113 while not (quitting ):
109114 options_index = question_menu .show ()
110115 try :
111- options_choice = options [options_index ]
116+ question_link = self . questions_data [options_index ][ 2 ]
112117 except Exception :
113118 return
114119 else :
115- question_link = self .questions_data [options_index ][2 ]
116120 webbrowser .open (question_link )
117121
122+ def display_panel (self , questions_list ):
123+ self .populate_question_data (questions_list )
124+ self .populate_answer_data (questions_list )
125+ self .navigate_questions_panel ()
126+
118127class Utility ():
119128 def __init__ (self ):
120129 # the parent url
@@ -128,6 +137,22 @@ def __get_search_url(self, question, tags):
128137 """
129138 return f"{ self .search_content_url } /2.2/search/advanced?order=desc&sort=relevance&tagged={ tags } &title={ question } &site=stackoverflow"
130139
140+ def get_batch_ques_url (self , ques_id_list ):
141+ """
142+ Returns URL which contains ques_ids which can be use to get
143+ get the details of all the corresponding questions
144+ """
145+ batch_ques_id = ""
146+ for question_id in ques_id_list :
147+ batch_ques_id += str (question_id ) + ";"
148+ return f"{ self .search_content_url } /2.2/questions/{ batch_ques_id [:- 1 ]} ?order=desc&sort=votes&site=stackoverflow&filter=!--1nZwsgqvRX"
149+
150+ def get_batch_ans_url (self , ques_id_list ):
151+ batch_ques_id = ""
152+ for question_id in ques_id_list :
153+ batch_ques_id += str (question_id ) + ";"
154+ return f"{ self .search_content_url } /2.2/questions/{ batch_ques_id [:- 1 ]} /answers?order=desc&sort=votes&site=stackoverflow&filter=!--1nZwsgqvRX"
155+
131156 def make_request (self , que , tag : str ):
132157 """
133158 This function uses the requests library to make the rest api call to the stackexchange server.
@@ -159,10 +184,13 @@ def get_que(self, json_data):
159184 return que_id
160185
161186 def get_ans (self , questions_list ):
162- stackoverflow_panel = Questions_Panel_stackoverflow ()
163- stackoverflow_panel .populate_question_data (questions_list )
164- stackoverflow_panel .populate_answer_data ()
165- stackoverflow_panel .navigate_questions_panel ()
187+ """
188+ This Function creates QuestionsPanel_stackoverflow class which supports
189+ Rendering, navigation, searching and redirecting capabilities
190+ """
191+ stackoverflow_panel = QuestionsPanel_stackoverflow ()
192+ stackoverflow_panel .display_panel (questions_list )
193+ # Support for reddit searching can also be implemented from here
166194
167195 # Get an access token and extract to a JSON file "access_token.json"
168196 @classmethod
0 commit comments