replbase 0.0.17__tar.gz → 0.0.18__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: replbase
3
- Version: 0.0.17
3
+ Version: 0.0.18
4
4
  Summary: "Combination of other REPL tools into a reusable class that generates a REPL"
5
5
  License: MIT
6
6
  Author: Joseph Bochinski
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [tool.poetry]
6
6
  name = "replbase"
7
- version = "0.0.17"
7
+ version = "0.0.18"
8
8
  description = "\"Combination of other REPL tools into a reusable class that generates a REPL\""
9
9
  authors = [ "Joseph Bochinski <stirgejr@gmail.com>",]
10
10
  license = "MIT"
@@ -0,0 +1,5 @@
1
+ """ Package for the ReplBase project. """
2
+
3
+ from replbase.repl_base import ReplBase, ReplTheme, SuggestFromLs, TestRepl
4
+
5
+ __all__ = ["ReplBase", "ReplTheme", "SuggestFromLs", "TestRepl"]
@@ -23,11 +23,15 @@ from dataclasses import dataclass, field
23
23
  from typing import Any, Callable, Literal
24
24
 
25
25
  from prompt_toolkit import PromptSession
26
+ from prompt_toolkit.buffer import Buffer
27
+ from prompt_toolkit.document import Document
28
+ from prompt_toolkit.auto_suggest import AutoSuggest, Suggestion
26
29
  from prompt_toolkit.history import FileHistory
27
30
  from prompt_toolkit.completion import WordCompleter
28
31
  from prompt_toolkit.styles import Style
29
32
  from ptpython.repl import embed
30
33
  from rich.console import Console
34
+ from rich.theme import Theme
31
35
 
32
36
  # endregion Imports
33
37
 
@@ -45,6 +49,27 @@ def is_num_str(val: str) -> bool:
45
49
  return bool(re.match(r"^-?\d+(\.\d+)?$", val))
46
50
 
47
51
 
52
+ @dataclass
53
+ class ReplTheme(Theme):
54
+ title: str = "bold cyan"
55
+ prompt: str = "bold green"
56
+ warn: str = "bold yellow"
57
+ error: str = "bold red"
58
+ cmd_name: str = "bold green"
59
+ cmd_desc: str = "cyan"
60
+ exit_kw: str = "bold green"
61
+ exit_str: str = "cyan"
62
+ greeting: str = "cyan"
63
+ addl_styles: dict = None
64
+
65
+ def __post_init__(self) -> None:
66
+ styles = dict(vars(self))
67
+ extras = styles.pop("addl_styles", {})
68
+ if extras:
69
+ styles.update(extras)
70
+ super().__init__(styles)
71
+
72
+
48
73
  @dataclass
49
74
  class ReplCommand:
50
75
  """Class definition for a provided CLI REPL command"""
@@ -65,7 +90,7 @@ class ReplBase:
65
90
  title: str = None
66
91
  """Title of the CLI REPL Prompt"""
67
92
 
68
- exit_keywords: list[str] = None # field(default_factory=list)
93
+ exit_keywords: list[str] = None
69
94
  """List of strings that cause the REPL to close, defaults to x, q,
70
95
  exit, and quit"""
71
96
 
@@ -75,6 +100,8 @@ class ReplBase:
75
100
  color_system: ColorSystem = None
76
101
  """Color syste for the rich console"""
77
102
 
103
+ theme: ReplTheme | dict = None
104
+
78
105
  console: Console = None
79
106
  """ Rich Console instance """
80
107
 
@@ -84,17 +111,19 @@ class ReplBase:
84
111
  temp_file: str = None
85
112
  """Path to prompt temporary file"""
86
113
 
87
- style: dict | Style = None # field(default_factory=dict)
114
+ style: dict | Style = None
88
115
  """Style for the prompt"""
89
116
 
90
117
  ignore_case: bool = None
91
118
  """Ignore case setting for the WordCompleter instance"""
92
119
 
93
- commands: dict[str, ReplCommand] = None # field(default_factory=dict)
120
+ commands: dict[str, ReplCommand] = None
94
121
  """Command dictionary for prompt_toolkit. Keys are command names,
95
122
  values are the corresponding description/help text"""
96
123
 
97
- parent: ReplBase = None
124
+ parent: ReplBase | dict = None
125
+
126
+ session: PromptSession = None
98
127
 
99
128
  def __post_init__(self) -> None:
100
129
  if isinstance(self.commands, dict):
@@ -110,20 +139,33 @@ class ReplBase:
110
139
  self.exit_keywords = self.exit_keywords or ["x", "q", "exit", "quit"]
111
140
 
112
141
  exit_kw_str = ", ".join(
113
- f'[bold green]"{kw}"[/bold green]' for kw in self.exit_keywords
142
+ f'[exit_kw]"{kw}"[/exit_kw]' for kw in self.exit_keywords
114
143
  )
115
144
  exit_kw_pref = "Type one of " if len(self.exit_keywords) > 1 else "Type "
116
- exit_str = f"[cyan]{exit_kw_pref}{exit_kw_str} to exit[/cyan]"
145
+ exit_str = f"[exit_str]{exit_kw_pref}{exit_kw_str} to exit[/exit_str]"
117
146
 
118
147
  self.init_prompt = self.init_prompt or [
119
- f"[bold cyan]<<| {self.title} |>>[/bold cyan]",
148
+ f"[title]<<| {self.title} |>>[/title]",
120
149
  exit_str,
121
- '[cyan]Type [bold green]"help"[/bold green] to view available commands.',
150
+ '[greeting]Type [cmd_name]"help"[/cmd_name] to view available commands.[/greeting]',
122
151
  ]
123
152
 
124
153
  self.color_system = self.color_system or "truecolor"
125
154
 
126
- self.console = Console(color_system=self.color_system)
155
+ if isinstance(self.theme, dict):
156
+ props = list(dict(vars(ReplTheme())).keys())
157
+ init = {"addl_styles": {}}
158
+ for key, value in self.theme.items():
159
+ if key in props:
160
+ init[key] = value
161
+ else:
162
+ init["addl_styles"][key] = value
163
+
164
+ self.theme = ReplTheme(**init)
165
+ elif self.theme is None:
166
+ self.theme = ReplTheme()
167
+
168
+ self.console = Console(color_system=self.color_system, theme=self.theme)
127
169
 
128
170
  self.history = self.history or os.path.expanduser(
129
171
  "~/.config/.prompt_history"
@@ -187,8 +229,10 @@ class ReplBase:
187
229
  """Shortcut to console.print"""
188
230
  self.console.print(*args)
189
231
 
190
- def input(self, *args) -> str:
232
+ def input(self, *args, suggestions: AutoSuggest = None) -> str:
191
233
  """Shortcut to console.input"""
234
+ if self.session:
235
+ return self.session.prompt(*args, auto_suggest=suggestions)
192
236
  return self.console.input(*args)
193
237
 
194
238
  def input_int(self, *args) -> int:
@@ -297,7 +341,7 @@ class ReplBase:
297
341
 
298
342
  for cmd_name, cmd in self.commands.items():
299
343
  self.print(
300
- f"[bold green]{cmd_name}:[/bold green] [cyan]{cmd.help_txt}[/cyan]"
344
+ f"[cmd_name]{cmd_name}:[/cmd_name] [cmd_desc]{cmd.help_txt}[/cmd_desc]"
301
345
  )
302
346
 
303
347
  def print_prompt(self) -> None:
@@ -316,7 +360,7 @@ class ReplBase:
316
360
  self.get_cmd_names(), ignore_case=self.ignore_case
317
361
  )
318
362
 
319
- session = PromptSession(
363
+ self.session = PromptSession(
320
364
  completer=completer,
321
365
  style=self.style,
322
366
  history=FileHistory(self.history),
@@ -327,29 +371,23 @@ class ReplBase:
327
371
 
328
372
  while True:
329
373
  try:
330
- user_input = session.prompt("> ", complete_while_typing=True)
374
+ user_input = self.session.prompt("> ", complete_while_typing=True)
331
375
 
332
376
  if user_input.lower() in ["help", "h"]:
333
377
  self.show_help()
334
378
  elif user_input.lower() in self.exit_keywords:
335
- self.print(
336
- f"[bold yellow]Exiting REPL ({self.title})...[/bold yellow]"
337
- )
379
+ self.print(f"[warn]Exiting REPL ({self.title})...[/warn]")
338
380
  break
339
381
  else:
340
382
  args = shlex.split(user_input)
341
383
  if not args:
342
- self.print(
343
- "[bold yellow][WARNING]: No command provided[/bold yellow]"
344
- )
384
+ self.print("[warn][WARNING]: No command provided[/warn]")
345
385
  continue
346
386
 
347
387
  cmd = self.commands.get(args[0])
348
388
 
349
389
  if not cmd:
350
- self.print(
351
- "[bold yellow][WARNING]: Invalid command[/bold yellow]"
352
- )
390
+ self.print("[warn][WARNING]: Invalid command[/warn]")
353
391
  continue
354
392
 
355
393
  cmd_args = args[1:]
@@ -372,18 +410,44 @@ class ReplBase:
372
410
  cmd.command(*cmd_args)
373
411
  else:
374
412
  self.print(
375
- "[bold yellow][WARNING]: No function provided for command[/bold yellow]"
413
+ "[warn][WARNING]: No function provided for command[/warn]"
376
414
  )
377
415
  except (EOFError, KeyboardInterrupt):
378
- self.print(
379
- f"[bold yellow]Exiting REPL ({self.title})...[/bold yellow]"
380
- )
416
+ self.print(f"[warn]Exiting REPL ({self.title})...[/warn]")
381
417
  break
382
418
 
383
419
  if self.parent:
384
420
  self.parent.print_prompt()
385
421
 
386
422
 
423
+ class SuggestFromLs(AutoSuggest):
424
+
425
+ def get_suggestion(
426
+ self, buffer: Buffer, document: Document
427
+ ) -> Suggestion | None:
428
+ files = os.listdir()
429
+
430
+ # Consider only the last line for the suggestion.
431
+ text = document.text.rsplit("\n", 1)[-1]
432
+
433
+ if text.strip():
434
+ for item in files:
435
+ if item.lower().startswith(text.lower()):
436
+ return Suggestion(item[len(text) :])
437
+ return None
438
+
439
+
440
+ @dataclass
441
+ class TestRepl(ReplBase):
442
+ def __post_init__(self) -> None:
443
+ super().__post_init__()
444
+ self.add_command("test_cmd", self.test_cmd, help_txt="Test command")
445
+
446
+ def test_cmd(self) -> None:
447
+ user_input = self.input("Testing prompt: ", suggestions=SuggestFromLs())
448
+ self.print(user_input)
449
+
450
+
387
451
  # endregion Classes
388
452
 
389
453
 
@@ -1,5 +0,0 @@
1
- """ Package for the ReplBase project. """
2
-
3
- from replbase.repl_base import ReplBase
4
-
5
- __all__ = ["ReplBase"]
File without changes
File without changes