25
25
import re
26
26
from typing import TYPE_CHECKING
27
27
28
+ import aiohttp
28
29
import discord
29
30
30
31
import core
35
36
GITHUB_ISSUE_URL = "https://github.com/{}/issues/{}"
36
37
LIB_ISSUE_REGEX = re .compile (r"(?P<lib>[a-z]+)?##(?P<number>[0-9]+)" , flags = re .IGNORECASE )
37
38
39
+ GITHUB_BASE_URL = "https://github.com/"
40
+ GITHUB_RAW_CONTENT_URL = "https://raw.githubusercontent.com/"
41
+
38
42
aliases = [
39
43
(("wavelink" , "wave" , "wl" ), "PythonistaGuild/Wavelink" ),
40
44
(("discordpy" , "discord" , "dpy" ), "Rapptz/discord.py" ),
46
50
class GitHub (core .Cog ):
47
51
def __init__ (self , bot : Bot ) -> None :
48
52
self .bot : Bot = bot
53
+ self .code_highlight_emoji = "📃"
54
+
55
+ def _strip_content_path (self , url : str ) -> str :
56
+ file_path = url [len (GITHUB_BASE_URL ):]
57
+ return file_path
58
+
59
+ async def format_highlight_block (self , url : str , line_adjustment : int = 10 ):
60
+ try :
61
+ highlighted_line = int (url .split ("#L" )[1 ]) # seperate the #L{n} highlight
62
+ except :
63
+ return None
64
+
65
+ file_path = self ._strip_content_path (url )
66
+ raw_url = GITHUB_RAW_CONTENT_URL + file_path .replace ("blob/" , "" ) # Convert it to a raw user content URL
67
+
68
+ code = ""
69
+ async with aiohttp .ClientSession () as session :
70
+ async with session .get (raw_url ) as r :
71
+ if r .status == 404 :
72
+ return
73
+
74
+ code += await r .text ()
75
+
76
+ code = code .splitlines ()
77
+
78
+ code_block_dict = {"lines" : {}}
79
+ j = 0
80
+ for i in code :
81
+ # populate the dict
82
+ code_block_dict ["lines" ][j ] = i
83
+ j += 1
84
+
85
+ code_block_dict ["lines" ][j ] = "\n "
86
+
87
+ line_list = code_block_dict ["lines" ]
88
+
89
+ if highlighted_line - 1 not in line_list :
90
+ return None
91
+
92
+ bound_adj = line_adjustment # adjustment for upper and lower bound display
93
+ _minBoundary = (highlighted_line - 1 - bound_adj )
94
+ _maxBoundary = (highlighted_line - 1 + bound_adj )
95
+
96
+ # loop through all the lines, and adjust the formatting
97
+ msg = "```ansi\n "
98
+ key = _minBoundary
99
+ while key <= _maxBoundary :
100
+ currLineNum = str (key + 1 )
101
+ # insert a space if there is no following char before the first character...
102
+ if key + 1 == highlighted_line :
103
+ highlighted_msg_format = "\u001b [0;37m\u001b [4;31m{} {}\u001b [0;0m\n " .format (
104
+ currLineNum , line_list [key ]
105
+ )
106
+
107
+ msg += highlighted_msg_format
108
+ else :
109
+ display_str = "{} {}\n " if line_list .get (key ) is not None else "" # if we hit the end of the file, just write an empty string
110
+ msg += display_str .format (currLineNum , line_list .get (key ))
111
+ key += 1
112
+
113
+ msg += "\n ```"
114
+
115
+ github_dict = {
116
+ "path" : file_path ,
117
+ "min" : _minBoundary if _minBoundary > 0 else highlighted_line , # Do not display negative numbers if >0
118
+ "max" : _maxBoundary ,
119
+ "msg" : msg
120
+ }
121
+ return github_dict
49
122
50
123
@core .Cog .listener ()
51
124
async def on_message (self , message : discord .Message ) -> None :
@@ -60,6 +133,35 @@ async def on_message(self, message: discord.Message) -> None:
60
133
61
134
await message .channel .send (GITHUB_ISSUE_URL .format (lib , issue ))
62
135
136
+ codeSegment = await self .format_highlight_block (message .content )
137
+
138
+ if codeSegment is None :
139
+ return
140
+
141
+ await message .add_reaction (self .code_highlight_emoji )
142
+
143
+ path = codeSegment ['path' ]
144
+ _min = codeSegment ['min' ]
145
+ _max = codeSegment ['max' ]
146
+ code_fmt = codeSegment ['msg' ]
147
+
148
+ def check (reaction , user ):
149
+ return reaction .emoji == self .code_highlight_emoji and user != self .bot .user \
150
+ and message .id == reaction .message .id
151
+
152
+ await self .bot .wait_for ("reaction_add" , check = check )
153
+
154
+ code_display_msg = await message .channel .send (
155
+ content = "Showing lines `{}` - `{}` in: `{}`...\n {}" .format (_min , _max , path , code_fmt ),
156
+ suppress_embeds = True
157
+ )
158
+
159
+ await self .bot .wait_for ("reaction_remove" , check = check )
160
+ await code_display_msg .delete ()
161
+
162
+ # clean up reactions
163
+ await message .clear_reactions ()
164
+
63
165
64
166
async def setup (bot : Bot ) -> None :
65
167
await bot .add_cog (GitHub (bot ))
0 commit comments