Add hooke.playlist.NoteIndexList and refactor exception handling in commandline.
[hooke.git] / hooke / plugin / playlist.py
1 """Defines :class:`PlaylistPlugin` several associated
2 :class:`hooke.plugin.Command`\s for handling :mod:`hooke.playlist`
3 classes.
4 """
5
6 import glob
7
8 from ..command import Command, Argument, Failure
9 from ..playlist import FilePlaylist
10 from ..plugin import Builtin
11
12
13 class PlaylistPlugin (Builtin):
14     def __init__(self):
15         super(PlaylistPlugin, self).__init__(name='playlist')
16
17     def commands(self):
18         return [NextCommand(), PreviousCommand(), JumpCommand(),
19                 SaveCommand(), LoadCommand(),
20                 AddCommand(), AddGlobCommand(),
21                 RemoveCommand(), FilterCommand()]
22
23
24 # Define common or complicated arguments
25
26 def current_playlist_callback(hooke, command, argument, value):
27     playlist = hooke.playlists.current()
28     if playlist == None:
29         raise Failure('No playlists loaded')
30     return playlist
31
32 PlaylistArgument = Argument(
33     name='playlist', type='playlist', callback=current_playlist_callback,
34     help="""
35 :class:`hooke.plugin.playlist.Playlist` to act on.  Defaults to the
36 current playlist.
37 """.strip())
38
39 def playlist_name_callback(hooke, command, argument, value):
40         return hooke.playlists.free_name()
41
42 PlaylistNameArgument = Argument(
43     name='name', type='string', optional=True, callback=playlist_name_callback,
44     help="""
45 Name of the new playlist (defaults to an auto-generated name).
46 """.strip())
47
48
49 # Define commands
50
51 class NextCommand (Command):
52     """Move playlist to the next curve.
53     """
54     def __init__(self):
55         super(NextCommand, self).__init__(
56             name='next curve',
57             arguments=[PlaylistArgument],
58             help=self.__doc__)
59
60     def _run(self, hooke, inqueue, outqueue, params):
61         params['playlist'].next()
62
63 class PreviousCommand (Command):
64     """Move playlist to the previous curve.
65     """
66     def __init__(self):
67         super(PreviousCommand, self).__init__(
68             name='previous curve',
69             arguments=[PlaylistArgument],
70             help=self.__doc__)
71
72     def _run(self, hooke, inqueue, outqueue, params):
73         params['playlist'].previous()
74
75 class JumpCommand (Command):
76     """Move playlist to a given curve.
77     """
78     def __init__(self):
79         super(JumpCommand, self).__init__(
80             name='jump to curve',
81             arguments=[
82                 PlaylistArgument,
83                 Argument(name='index', type='int', optional=False, help="""
84 Index of target curve.
85 """.strip()),
86                 ],
87             help=self.__doc__)
88
89     def _run(self, hooke, inqueue, outqueue, params):
90         params['playlist'].jump(params['index'])
91
92 class SaveCommand (Command):
93     """Save a playlist.
94     """
95     def __init__(self):
96         super(SaveCommand, self).__init__(
97             name='save playlist',
98             arguments=[
99                 PlaylistArgument,
100                 Argument(name='output', type='file',
101                          help="""
102 File name for the output playlist.  Defaults to overwriting the input
103 playlist.
104 """.strip()),
105                 ],
106             help=self.__doc__)
107
108     def _run(self, hooke, inqueue, outqueue, params):
109         params['playlist'].save(params['output'])
110
111 class LoadCommand (Command):
112     """Load a playlist.
113     """
114     def __init__(self):
115         super(LoadCommand, self).__init__(
116             name='load playlist',
117             arguments=[
118                 Argument(name='input', type='file', optional=False,
119                          help="""
120 File name for the input playlist.
121 """.strip()),
122                 Argument(name='drivers', type='driver', optional=False,
123                          count=-1,
124                          help="""
125 Drivers for loading curves.
126 """.strip()),
127                 ],
128             help=self.__doc__)
129
130     def _run(self, hooke, inqueue, outqueue, params):
131         p = FilePlaylist(drivers=params['drivers'], path=params['input'])
132         p.load()
133         hooke.playlists.append(p)
134         outqueue.put(p)
135
136 class AddCommand (Command):
137     """Add a curve to a playlist.
138     """
139     def __init__(self):
140         super(AddCommand, self).__init__(
141             name='add curve to playlist',
142             arguments=[
143                 PlaylistArgument,
144                 Argument(name='input', type='file', optional=False,
145                          help="""
146 File name for the input :class:`hooke.curve.Curve`.
147 """.strip()),
148                 Argument(name='info', type='dict', optional=True,
149                          help="""
150 Additional information for the input :class:`hooke.curve.Curve`.
151 """.strip()),
152                 ],
153             help=self.__doc__)
154
155     def _run(self, hooke, inqueue, outqueue, params):
156         params['playlist'].append_curve_by_path(params['input'],
157                                                 params['info'])
158
159 class AddGlobCommand (Command):
160     """Add curves to a playlist with file globbing.
161
162     Adding lots of files one at a time can be tedious.  With this
163     command you can use globs (`data/curves/*.dat`) to add curves
164     for all matching files at once.
165     """
166     def __init__(self):
167         super(AddGlobCommand, self).__init__(
168             name='glob curves to playlist',
169             arguments=[
170                 PlaylistArgument,
171                 Argument(name='input', type='glob', optional=False,
172                          help="""
173 File name glob for the input :class:`hooke.curve.Curve`.
174 """.strip()),
175                 Argument(name='info', type='dict', optional=True,
176                          help="""
177 Additional information for the input :class:`hooke.curve.Curve`.
178 """.strip()),
179                 ],
180             help=self.__doc__)
181
182     def _run(self, hooke, inqueue, outqueue, params):
183         for path in sorted(glob.glob(params['input'])):
184             params['playlist'].append_curve_by_path(path, params['info'])
185
186 class RemoveCommand (Command):
187     """Remove a curve from a playlist.
188     """
189     def __init__(self):
190         super(RemoveCommand, self).__init__(
191             name='remove curve from playlist',
192             arguments=[
193                 PlaylistArgument,
194                 Argument(name='index', type='int', optional=False, help="""
195 Index of target curve.
196 """.strip()),
197                 ],
198             help=self.__doc__)
199
200     def _run(self, hooke, inqueue, outqueue, params):
201         params['playlist'].pop(params['index'])
202         params['playlist'].jump(params._index)
203
204 class FilterCommand (Command):
205     """Create a subset playlist via a selection function.
206
207     Removing lots of curves one at a time can be tedious.  With this
208     command you can use a function `filter` to select the curves you
209     wish to keep.
210     """
211     def __init__(self):
212         super(FilterCommand, self).__init__(
213             name='filter playlist',
214             arguments=[
215                 PlaylistArgument,
216                 PlaylistNameArgument,
217                 Argument(name='filter', type='function', optional=False,
218                          help="""
219 Function returning `True` for "good" curves.  `filter(curve) -> True/False`.
220 """.strip()),
221                 ],
222             help=self.__doc__)
223
224     def _run(self, hooke, inqueue, outqueue, params):
225         p = params['playlist'].filter(params['filter'])
226         hooke.playlists.add(p)
227         outqueue.put(p)