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