bug fixes, console themes, help interface
This commit is contained in:
+19
-2
@@ -1,10 +1,13 @@
|
||||
from prompt_toolkit import prompt
|
||||
from prompt_toolkit.completion import Completer, Completion
|
||||
from prompt_toolkit import print_formatted_text, HTML
|
||||
from groove.console import Console
|
||||
|
||||
|
||||
|
||||
class BasePrompt(Completer):
|
||||
|
||||
def __init__(self, manager=None, parent=None):
|
||||
def __init__(self, manager=None, console=None, parent=None):
|
||||
super(BasePrompt, self).__init__()
|
||||
|
||||
if (not manager and not parent): # pragma: no cover
|
||||
@@ -14,6 +17,14 @@ class BasePrompt(Completer):
|
||||
self._values = []
|
||||
self._parent = parent
|
||||
self._manager = manager
|
||||
self._console = None
|
||||
self._theme = None
|
||||
|
||||
@property
|
||||
def console(self):
|
||||
if not self._console:
|
||||
self._console = Console(color_system='truecolor')
|
||||
return self._console
|
||||
|
||||
@property
|
||||
def usage(self):
|
||||
@@ -56,10 +67,16 @@ class BasePrompt(Completer):
|
||||
except NotImplementedError:
|
||||
pass
|
||||
|
||||
def help(self, parts):
|
||||
self.console.print(
|
||||
getattr(self, parts[0]).__doc__ if parts else self.help_text
|
||||
)
|
||||
return True
|
||||
|
||||
def start(self, cmd=''):
|
||||
while True:
|
||||
if not cmd:
|
||||
cmd = prompt(f'{self.prompt} ', completer=self)
|
||||
cmd = self.console.prompt(self.prompt, completer=self)
|
||||
if not cmd:
|
||||
return
|
||||
cmd, *parts = cmd.split()
|
||||
|
||||
@@ -11,9 +11,12 @@ class CommandPrompt(BasePrompt):
|
||||
def __init__(self, manager):
|
||||
super().__init__(manager=manager)
|
||||
self._playlist = None
|
||||
self._prompt = "Groove on Demand interactive shell. Try 'help' for help.\ngroove>"
|
||||
self._completer = None
|
||||
self._commands = None
|
||||
self._prompt = [
|
||||
"[help]Groove on Demand interactive shell. Try 'help' for help.[/help]",
|
||||
"groove"
|
||||
]
|
||||
|
||||
@property
|
||||
def playlist(self):
|
||||
|
||||
+83
-22
@@ -1,23 +1,67 @@
|
||||
from .base import BasePrompt
|
||||
|
||||
from prompt_toolkit import prompt
|
||||
from rich import print
|
||||
import os
|
||||
|
||||
from sqlalchemy.exc import NoResultFound
|
||||
from textwrap import dedent, wrap
|
||||
|
||||
from groove import db
|
||||
from groove.exceptions import PlaylistValidationError
|
||||
|
||||
|
||||
class _playlist(BasePrompt):
|
||||
"""
|
||||
"""
|
||||
|
||||
def __init__(self, parent, manager=None):
|
||||
super().__init__(manager=manager, parent=parent)
|
||||
self._parent = parent
|
||||
self._prompt = ''
|
||||
self._commands = None
|
||||
|
||||
@property
|
||||
def help_text(self):
|
||||
synopsis = (
|
||||
f"You are currently editing the [b]{self.parent.playlist.name}[/b]"
|
||||
f" playlist. From this prompt you can quickly append new tracks "
|
||||
f"to the playlist. You can invoke your editor "
|
||||
f"([link]{os.environ['EDITOR']}[/link]) to change the playlist "
|
||||
f"name and description, or reorder or remove tracks. You can also "
|
||||
f"delete the playlist."
|
||||
)
|
||||
|
||||
try:
|
||||
width = int(os.environ.get('CONSOLE_WIDTH', '80'))
|
||||
except ValueError:
|
||||
width = 80
|
||||
synopsis = '\n '.join(wrap(synopsis, width=width))
|
||||
|
||||
return dedent(f"""
|
||||
[title]WORKING WITH PLAYLISTS[/title]
|
||||
|
||||
{synopsis}
|
||||
|
||||
[title]USAGE[/title]
|
||||
|
||||
[link]playlist> COMMAND [ARG ..][/link]
|
||||
|
||||
[title]COMMANDS[/title]
|
||||
[help]
|
||||
[b]add[/b] Add one or more tracks to the playlist
|
||||
[b]edit[/b] Open the playlist in the system editor
|
||||
[b]show[/b] Display the complete playlist
|
||||
[b]delete[/b] Delete the playlist
|
||||
[b]help[/b] This message
|
||||
|
||||
Try 'help command' for command-specific help.[/help]
|
||||
""")
|
||||
|
||||
@property
|
||||
def prompt(self):
|
||||
return f"{self.parent.playlist}\n{self.parent.playlist.slug}> "
|
||||
return [
|
||||
"",
|
||||
"[help]Available commands: add, edit, show, delete, help. Hit Enter to return.[/help]",
|
||||
f"[prompt]{self.parent.playlist.slug}[/prompt]",
|
||||
]
|
||||
|
||||
@property
|
||||
def values(self):
|
||||
@@ -27,32 +71,41 @@ class _playlist(BasePrompt):
|
||||
def commands(self):
|
||||
if not self._commands:
|
||||
self._commands = {
|
||||
'show': self.show,
|
||||
'delete': self.delete,
|
||||
'add': self.add,
|
||||
'show': self.show,
|
||||
'edit': self.edit,
|
||||
'help': self.help
|
||||
}
|
||||
return self._commands
|
||||
|
||||
def process(self, cmd, *parts):
|
||||
if cmd in self.commands:
|
||||
return True if self.commands[cmd](parts) else False
|
||||
print(f"Command not understood: {cmd}")
|
||||
self.parent.console.error(f"Command not understood: {cmd}")
|
||||
return True
|
||||
|
||||
def show(self, parts):
|
||||
print(self.parent.playlist)
|
||||
def edit(self, *parts):
|
||||
try:
|
||||
self.parent.playlist.edit()
|
||||
except PlaylistValidationError as e:
|
||||
self.parent.console.error(f"Changes were not saved: {e}")
|
||||
else:
|
||||
self.show()
|
||||
return True
|
||||
|
||||
def edit(self, parts):
|
||||
self.parent.playlist.edit()
|
||||
def show(self, *parts):
|
||||
self.parent.console.print(self.parent.playlist.as_richtext)
|
||||
return True
|
||||
|
||||
def add(self, parts):
|
||||
print("Add tracks one at a time by title. ENTER to finish.")
|
||||
def add(self, *parts):
|
||||
self.parent.console.print(
|
||||
"Add tracks one at a time by title. Hit Enter to finish."
|
||||
)
|
||||
added = False
|
||||
while True:
|
||||
text = prompt(
|
||||
' ?',
|
||||
text = self.parent.console.prompt(
|
||||
[' ?'],
|
||||
completer=self.manager.fuzzy_table_completer(
|
||||
db.track,
|
||||
db.track.c.relpath,
|
||||
@@ -61,8 +114,11 @@ class _playlist(BasePrompt):
|
||||
complete_in_thread=True, complete_while_typing=True
|
||||
)
|
||||
if not text:
|
||||
if added:
|
||||
self.show()
|
||||
return True
|
||||
self._add_track(text)
|
||||
added = True
|
||||
|
||||
def _add_track(self, text):
|
||||
sess = self.parent.manager.session
|
||||
@@ -70,20 +126,25 @@ class _playlist(BasePrompt):
|
||||
track = sess.query(db.track).filter(db.track.c.relpath == text).one()
|
||||
self.parent.playlist.create_entries([track])
|
||||
except NoResultFound:
|
||||
print("No match for '{text}'")
|
||||
self.parent.console.error("No match for '{text}'")
|
||||
return
|
||||
return text
|
||||
|
||||
def delete(self, parts):
|
||||
res = prompt(
|
||||
'Type DELETE to permanently delete the playlist '
|
||||
f'"{self.parent.playlist.record.name}".\nDELETE {self.prompt}'
|
||||
)
|
||||
def delete(self, *parts):
|
||||
res = self.parent.console.prompt([
|
||||
f"[error]Type [b]DELETE[/b] to permanently delete the playlist "
|
||||
f'"{self.parent.playlist.record.name}".[/error]',
|
||||
f"[prompt]DELETE {self.parent.playlist.slug}[/prompt]",
|
||||
])
|
||||
if res != 'DELETE':
|
||||
print("Delete aborted. No changes have been made.")
|
||||
self.parent.console.error("Delete aborted. No changes have been made.")
|
||||
return True
|
||||
|
||||
self.parent.playlist.delete()
|
||||
print("Deleted the playlist.")
|
||||
self.parent.console.print("Deleted the playlist.")
|
||||
self.parent._playlist = None
|
||||
return False
|
||||
|
||||
def start(self):
|
||||
self.show()
|
||||
super().start()
|
||||
|
||||
Reference in New Issue
Block a user