Skip to content

Commit 92d3e5e

Browse files
authored
Add tip when using a redundant rtfm selector (#51)
Add a tip to rtfm/rtfs and update docs/ux around them
1 parent 87c69f4 commit 92d3e5e

File tree

2 files changed

+107
-89
lines changed

2 files changed

+107
-89
lines changed

core/utils/paginator.py

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,13 @@
2929
from discord import ui # shortcut because I'm lazy
3030
from discord.ext.commands import CommandError, Paginator as _Paginator # type: ignore # why does this need a stub file?
3131
from discord.utils import MISSING
32+
from typing_extensions import Self
3233

34+
from core import Bot, Context
3335

34-
if TYPE_CHECKING:
35-
from typing_extensions import Self
3636

37-
from core import Context
37+
if TYPE_CHECKING:
38+
from discord.abc import MessageableChannel
3839

3940

4041
__all__ = ("CannotPaginate", "Pager", "KVPager", "TextPager")
@@ -61,19 +62,27 @@ def __init__(
6162
author: discord.User | discord.Member | None = None,
6263
author_url: str | None = None,
6364
stop: bool = False,
65+
reply_author_takes_paginator: bool = False,
6466
):
6567
super().__init__()
66-
self.bot = ctx.bot
67-
self.stoppable = stop
68-
self.ctx = ctx
69-
self.delete_after = delete_after
70-
self.entries = entries
71-
self.embed_author = author, author_url
72-
self.channel = ctx.channel
73-
self.author = ctx.author
74-
self.nocount = nocount
75-
self.title = title
76-
self.per_page = per_page
68+
self.bot: Bot = ctx.bot
69+
self.stoppable: bool = stop
70+
self.ctx: Context = ctx
71+
self.delete_after: bool = delete_after
72+
self.entries: list[Any] = entries
73+
self.embed_author: tuple[discord.User | discord.Member | None, str | None] = author, author_url
74+
self.channel: MessageableChannel = ctx.channel
75+
self.nocount: bool = nocount
76+
self.title: str | None = title
77+
self.per_page: int = per_page
78+
79+
if reply_author_takes_paginator:
80+
if ctx.replied_reference:
81+
self.author = ctx.replied_message.author
82+
else:
83+
self.author = ctx.author
84+
else:
85+
self.author = ctx.author
7786

7887
pages, left_over = divmod(len(self.entries), self.per_page)
7988
if left_over:
@@ -298,13 +307,21 @@ def prepare_embed(self, entries: list[Any], page: int, *, first: bool = False):
298307

299308
class TextPager(Pager):
300309
def __init__(
301-
self, ctx: Context, text: str, *, prefix: str = "```", suffix: str = "```", max_size: int = 2000, stop: bool = False
310+
self,
311+
ctx: Context,
312+
text: str,
313+
*,
314+
prefix: str = "```",
315+
suffix: str = "```",
316+
max_size: int = 2000,
317+
stop: bool = False,
318+
**kwargs: Any,
302319
) -> None:
303320
paginator = _Paginator(prefix=prefix, suffix=suffix, max_size=max_size - 200)
304321
for line in text.split("\n"):
305322
paginator.add_line(line)
306323

307-
super().__init__(ctx, entries=paginator.pages, per_page=1, show_entry_count=False, stop=stop)
324+
super().__init__(ctx, entries=paginator.pages, per_page=1, show_entry_count=False, stop=stop, **kwargs)
308325

309326
def get_page(self, page: int) -> Any:
310327
return self.entries[page - 1]

modules/manuals.py

Lines changed: 74 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,49 @@ def _smart_guess_lib(self, ctx: core.Context) -> LibEnum | None:
9797

9898
return None
9999

100+
async def get_lib(self, ctx: core.Context, query: str) -> tuple[LibEnum, str, str] | None: # enum, query, notice
101+
if not query:
102+
lib = self._smart_guess_lib(ctx)
103+
104+
if not lib:
105+
await ctx.reply("Sorry, I couldn't apply a default library to this channel. Try again with a library?")
106+
return None
107+
108+
await ctx.send(str(lib.value), reference=ctx.replied_message)
109+
return None
110+
111+
view = StringView(query)
112+
maybe_lib = view.get_word()
113+
view.skip_ws()
114+
final_query = view.read_rest()
115+
116+
tip = ""
117+
lib: LibEnum | None = None
118+
119+
if maybe_lib in lib_names:
120+
lib = lib_names[maybe_lib]
121+
else:
122+
maybe_lib = None
123+
final_query = query # ignore the stringview stuff then
124+
125+
if lib is None:
126+
lib = self._smart_guess_lib(ctx)
127+
128+
if lib is None:
129+
await ctx.reply("Sorry, I couldn't find a library that matched. Try again with a different library?")
130+
return None
131+
132+
elif (
133+
maybe_lib
134+
and isinstance(ctx.channel, discord.Thread)
135+
and ctx.channel.parent_id == constants.Channels.HELP_FORUM
136+
and lib == self._smart_guess_lib(ctx)
137+
):
138+
if 1006717008613740596 not in ctx.channel._applied_tags: # type: ignore # other-help tag, that one doesnt get a smart guess
139+
tip += "\n• Tip: Forum posts with tags will automatically have the relevant libraries used, no need to specify it!"
140+
141+
return lib, final_query, tip
142+
100143
@commands.command(
101144
"rtfm",
102145
brief="Searches documentation",
@@ -111,28 +154,18 @@ async def rtfm(self, ctx: core.Context, *, query: str) -> None:
111154
On its own it will do its best to figure out the most relevant documentation,
112155
but you can always specify by prefixing the query with the library you wish to use.
113156
The following libraries are supported (you can use either the full name or the shorthand):
114-
```
115-
- wavelink | wl
116-
- twitchio | tio
117-
- python | py
118-
- discordpy | dpy
119-
```
120157
121-
The following flags are available for this command:
122-
```
123-
- --labels (Include labels in search results)
124-
- --clear (Clearly labels labels with a `label:` prefix. If --labels has not be set it will be implicitly set)
125-
"""
126-
if not query:
127-
lib = self._smart_guess_lib(ctx)
158+
• wavelink | wl
159+
• twitchio | tio
160+
• python | py
161+
• discordpy | dpy
128162
129-
if not lib:
130-
await ctx.reply("Sorry, I couldn't apply a default library to this channel. Try again with a library?")
131-
return
132163
133-
await ctx.send(str(lib.value), reference=ctx.replied_message)
134-
return
164+
The following flags are available for this command:
135165
166+
• --labels (Include labels in search results)
167+
• --clear (Clearly labels labels with a `label:` prefix. If --labels has not be set it will be implicitly set)
168+
"""
136169
labels = False
137170
clear_labels = False
138171

@@ -144,26 +177,14 @@ async def rtfm(self, ctx: core.Context, *, query: str) -> None:
144177
labels = clear_labels = True # implicitly set --labels
145178
query = query.replace("--clear", "")
146179

147-
view = StringView(query)
148-
maybe_lib = view.get_word()
149-
view.skip_ws()
150-
final_query = view.read_rest()
151-
lib: LibEnum | None = None
152-
153-
if maybe_lib in lib_names:
154-
lib = lib_names[maybe_lib]
155-
else:
156-
final_query = query # ignore the stringview stuff then
157-
158-
if lib is None:
159-
lib = self._smart_guess_lib(ctx)
160-
161-
if lib is None:
162-
await ctx.reply("Sorry, I couldn't find a library that matched. Try again with a different library?")
180+
optional = await self.get_lib(ctx, query)
181+
if not optional:
163182
return
164183

184+
lib, final_query, tip = optional
185+
165186
if not final_query:
166-
await ctx.send(str(lib.value[0]), reference=ctx.replied_message)
187+
await ctx.send(str(lib.value[0]) + tip, reference=ctx.replied_message)
167188
return
168189

169190
url = self.target.with_path("/api/public/rtfm.sphinx").with_query(
@@ -196,7 +217,7 @@ async def rtfm(self, ctx: core.Context, *, query: str) -> None:
196217
e.description = "\n".join(f"[`{key}`]({url})" for key, url in matches["nodes"].items())
197218
e.set_author(name=f"Query Time: {float(matches['query_time']):.2f}")
198219

199-
await ctx.send(embed=e)
220+
await ctx.send(tip or None, embed=e)
200221

201222
@commands.command(
202223
name="rtfs",
@@ -212,53 +233,31 @@ async def rtfs(self, ctx: core.Context, *, query: str) -> None:
212233
On its own it will do its best to figure out the most relevant library,
213234
but you can always specify by prefixing the query with the library you wish to use.
214235
The following libraries are supported (you can use either the full name or the shorthand):
215-
```
216-
- wavelink | wl
217-
- twitchio | tio
218-
- discordpy | dpy
219-
- aiohttp |
220-
```
221236
222-
The following flags are available for this command:
223-
```
224-
- --source (Sends source code instead of links to the github repository)
225-
"""
226-
if not query:
227-
lib = self._smart_guess_lib(ctx)
237+
• wavelink | wl
238+
• twitchio | tio
239+
• discordpy | dpy
240+
• aiohttp |
228241
229-
if not lib:
230-
await ctx.reply("Sorry, I couldn't apply a default library to this channel. Try again with a library?")
231-
return
242+
The following flags are available for this command:
232243
233-
await ctx.send(str(lib.value), reference=ctx.replied_message)
234-
return
244+
• --source (Sends source code instead of links to the github repository)
245+
"""
235246

236247
source = False
237248

238249
if "--source" in query:
239250
source = True
240251
query = query.replace("--source", "")
241252

242-
view = StringView(query)
243-
maybe_lib = view.get_word()
244-
view.skip_ws()
245-
final_query = view.read_rest()
246-
lib: LibEnum | None = None
247-
248-
if maybe_lib in lib_names:
249-
lib = lib_names[maybe_lib]
250-
else:
251-
final_query = query # ignore the stringview stuff then
252-
253-
if lib is None:
254-
lib = self._smart_guess_lib(ctx)
255-
256-
if lib is None:
257-
await ctx.reply("Sorry, I couldn't find a library that matched. Try again with a different library?")
253+
optional = await self.get_lib(ctx, query)
254+
if not optional:
258255
return
259256

257+
lib, final_query, tip = optional
258+
260259
if not final_query:
261-
await ctx.reply(str(lib.value[0]))
260+
await ctx.reply(str(lib.value[0]) + tip)
262261
return
263262

264263
url = self.target.with_path("/api/public/rtfs").with_query(
@@ -291,7 +290,7 @@ async def rtfs(self, ctx: core.Context, *, query: str) -> None:
291290
out = [f"[{name}]({url})" for name, url in nodes.items()]
292291

293292
author: str = f"query Time: {float(matches['query_time']):.03f} • commit {matches['commit'][:6]}"
294-
footer: str = f"Is the api behind on commits? Use {discord.utils.escape_mentions(ctx.prefix)}rtfs-reload" # type: ignore
293+
footer: str | None = tip or None
295294

296295
embed: discord.Embed = discord.Embed(title=f"{lib.name.title()}: {final_query}", colour=lib.value[1])
297296
embed.description = "\n".join(out)
@@ -302,9 +301,11 @@ async def rtfs(self, ctx: core.Context, *, query: str) -> None:
302301

303302
else:
304303
n = next(iter(nodes.items()))
305-
await ctx.send(f"Showing source for `{n[0]}`\nCommit: {matches['commit'][:6]}", reference=ctx.replied_message)
304+
await ctx.send(
305+
f"Showing source for `{n[0]}`\nCommit: {matches['commit'][:6]}" + tip, reference=ctx.replied_message
306+
)
306307

307-
pages = TextPager(ctx, n[1], prefix="```py")
308+
pages = TextPager(ctx, n[1], prefix="```py", reply_author_takes_paginator=True)
308309
await pages.paginate()
309310

310311

0 commit comments

Comments
 (0)