33from __future__ import annotations
44
55import asyncio
6+ import dataclasses
67import enum
78import importlib .metadata
89import logging
910import optparse
1011from pathlib import Path
1112import sys
13+ from typing import Any
1214
1315from .bots import load_bot
1416from .common import PROGRAM , Config , UnreachableError , ensure_state_home
2830_logger = logging .getLogger (__name__ )
2931
3032
31- def new_parser () -> optparse .OptionParser :
33+ class Accept (enum .Enum ):
34+ """Valid change accept mode"""
35+
36+ MANUAL = 0
37+ MERGE = enum .auto ()
38+ MERGE_THEIRS = enum .auto ()
39+ MERGE_THEN_QUIT = enum .auto ()
40+
41+ def merge_strategy (self ) -> DraftMergeStrategy | None :
42+ match self :
43+ case Accept .MANUAL :
44+ return None
45+ case Accept .MERGE :
46+ return "ignore-all-space"
47+ case Accept .MERGE_THEIRS | Accept .MERGE_THEN_QUIT :
48+ return "theirs"
49+ case _:
50+ raise UnreachableError ()
51+
52+
53+ def _new_parser () -> optparse .OptionParser :
3254 parser = optparse .OptionParser (
3355 prog = PROGRAM ,
3456 version = importlib .metadata .version ("git_draft" ),
@@ -94,39 +116,24 @@ def callback(
94116 help = "edit prompt or template" ,
95117 action = "store_true" ,
96118 )
97-
98119 parser .add_option (
99120 "--no-accept" ,
100121 help = "do not merge draft" ,
101122 dest = "accept" ,
102123 action = "store_const" ,
103124 const = 0 ,
104125 )
126+ parser .add_option (
127+ "-f" ,
128+ "--format" ,
129+ dest = "format" ,
130+ help = "formatting string" ,
131+ )
105132
106133 return parser
107134
108135
109- class Accept (enum .Enum ):
110- """Valid change accept mode"""
111-
112- MANUAL = 0
113- MERGE = enum .auto ()
114- MERGE_THEIRS = enum .auto ()
115- MERGE_THEN_QUIT = enum .auto ()
116-
117- def merge_strategy (self ) -> DraftMergeStrategy | None :
118- match self :
119- case Accept .MANUAL :
120- return None
121- case Accept .MERGE :
122- return "ignore-all-space"
123- case Accept .MERGE_THEIRS | Accept .MERGE_THEN_QUIT :
124- return "theirs"
125- case _:
126- raise UnreachableError ()
127-
128-
129- def edit (* , path : Path | None = None , text : str | None = None ) -> str :
136+ def _edit (* , path : Path | None = None , text : str | None = None ) -> str :
130137 if sys .stdin .isatty ():
131138 return open_editor (text or "" , path )
132139 # We exit with a custom code to allow the caller to act accordingly.
@@ -145,12 +152,17 @@ def edit(*, path: Path | None = None, text: str | None = None) -> str:
145152 sys .exit (199 )
146153
147154
155+ def _format (props : Any , spec : str ) -> str :
156+ """Formats an instance of a dataclass using the provided pattern"""
157+ return spec .format (** dataclasses .asdict (props ))
158+
159+
148160_PROMPT_PLACEHOLDER = "Enter your prompt here..."
149161
150162
151163async def run () -> None : # noqa: PLR0912 PLR0915
152164 config = Config .load ()
153- (opts , args ) = new_parser ().parse_args ()
165+ (opts , args ) = _new_parser ().parse_args ()
154166
155167 log_path = ensure_state_home () / "log"
156168 if opts .log_path :
@@ -191,7 +203,7 @@ async def run() -> None: # noqa: PLR0912 PLR0915
191203 prompt = TemplatedPrompt .public (args [0 ], args [1 :])
192204 editable = opts .edit
193205 else :
194- prompt = edit (
206+ prompt = _edit (
195207 text = drafter .latest_draft_prompt () or _PROMPT_PLACEHOLDER
196208 ).strip ()
197209 if prompt .strip () == _PROMPT_PLACEHOLDER :
@@ -212,25 +224,27 @@ async def run() -> None: # noqa: PLR0912 PLR0915
212224 drafter .quit_folio ()
213225 case "list-events" :
214226 draft_id = args [0 ] if args else None
215- for line in drafter .list_draft_events (draft_id ):
216- print (line )
227+ spec = opts .format or "{occurred_at}\t {description}"
228+ for event_props in drafter .list_draft_events (draft_id ):
229+ print (_format (event_props , spec ))
217230 case "show-template" :
218231 if len (args ) != 1 :
219232 raise ValueError ("Expected exactly one argument" )
220233 name = args [0 ]
221234 meta = find_prompt_metadata (name )
222235 if opts .edit :
223236 if meta :
224- edit (path = meta .local_path (), text = meta .source ())
237+ _edit (path = meta .local_path (), text = meta .source ())
225238 else :
226- edit (path = PromptMetadata .local_path_for (name ))
239+ _edit (path = PromptMetadata .local_path_for (name ))
227240 else :
228241 if not meta :
229242 raise ValueError (f"No template named { name !r} " )
230243 print (meta .source ())
231244 case "list-templates" :
232- for line in list_templates ():
233- print (line )
245+ spec = opts .format or "{name}: {description}"
246+ for template_props in list_templates ():
247+ print (_format (template_props , spec ))
234248 case _:
235249 raise UnreachableError ()
236250
0 commit comments