88
99import sys
1010import click
11+ from pathlib import Path
1112from importlib import metadata
1213
14+ from mkdocs_note .config import MkdocsNoteConfig
15+ from mkdocs_note .utils .cli .new import NoteCreator
16+ from mkdocs_note .utils .cli .remove import NoteRemover
17+ from mkdocs_note .utils .cli .move import NoteMover
18+ from mkdocs_note .utils .cli .clean import NoteCleaner
19+
1320
1421def get_version ():
1522 """Get the version of mkdocs-note package.
@@ -99,27 +106,65 @@ def cli(ctx):
99106
100107
101108@cli .command ("new" )
102- @click .argument ("file_path" , required = False )
109+ @click .argument ("file_path" , required = True )
110+ @click .option (
111+ "--template" ,
112+ "-t" ,
113+ type = click .Path (exists = True , path_type = Path ),
114+ help = "Custom template file to use" ,
115+ )
103116@click .pass_context
104- def new_command (ctx , file_path ):
117+ def new_command (ctx , file_path , template ):
105118 """Create a new note file with proper asset structure.
106119
107120 \b
108121 Examples:
109122 mkdocs-note new docs/notes/my-note.md
110123 mkdocs-note new docs/notes/python/intro.md
124+ mkdocs-note new docs/notes/custom.md --template templates/custom.md
111125
112126 FILE_PATH: Path where the new note file should be created
113127 """
114- click .echo ("⚠️ 'new' command is not yet implemented" )
115- click .echo ("💡 This feature is being refactored" )
116- sys .exit (1 )
128+ try :
129+ # Load configuration
130+ config = MkdocsNoteConfig ()
131+ creator = NoteCreator (config )
132+
133+ # Convert to Path
134+ note_path = Path (file_path )
135+
136+ # Create the note
137+ result = creator .create_new_note (note_path , template_path = template )
138+
139+ if result .success :
140+ click .echo (f"✅ { result .message } " )
141+ click .echo (f"📝 Note: { result .data ['note_path' ]} " )
142+ click .echo (f"📁 Assets: { result .data ['asset_dir' ]} " )
143+ sys .exit (0 )
144+ else :
145+ click .echo (f"❌ Error: { result .message } " , err = True )
146+ sys .exit (1 )
147+
148+ except Exception as e :
149+ click .echo (f"❌ Unexpected error: { e } " , err = True )
150+ sys .exit (1 )
117151
118152
119153@cli .command ("remove" )
120- @click .argument ("file_path" , required = False )
154+ @click .argument ("file_path" , required = True )
155+ @click .option (
156+ "--keep-assets" ,
157+ is_flag = True ,
158+ help = "Keep the asset directory when removing the note" ,
159+ )
160+ @click .option (
161+ "--yes" ,
162+ "-y" ,
163+ is_flag = True ,
164+ help = "Skip confirmation prompt" ,
165+ )
121166@click .pass_context
122- def remove_command (ctx , file_path ):
167+ def remove_command (ctx , file_path , keep_assets , yes ):
123168 """Remove a note file and its corresponding asset directory.
124169
125170 \b
@@ -129,27 +174,74 @@ def remove_command(ctx, file_path):
129174 Examples:
130175 mkdocs-note remove docs/notes/test.md
131176 mkdocs-note rm docs/notes/test.md --yes
177+ mkdocs-note remove docs/notes/test.md --keep-assets
132178
133179 FILE_PATH: Path to the note file to remove
134180 """
135- click .echo ("⚠️ 'remove' command is not yet implemented" )
136- click .echo ("💡 This feature is being refactored" )
137- sys .exit (1 )
181+ try :
182+ note_path = Path (file_path )
183+
184+ # Check if file exists
185+ if not note_path .exists ():
186+ click .echo (f"❌ Error: File does not exist: { note_path } " , err = True )
187+ sys .exit (1 )
188+
189+ # Confirmation prompt (unless --yes)
190+ if not yes :
191+ asset_msg = "and its assets" if not keep_assets else "(keeping assets)"
192+ if not click .confirm (f"Remove { note_path } { asset_msg } ?" ):
193+ click .echo ("⚠️ Cancelled" )
194+ sys .exit (0 )
195+
196+ # Load configuration
197+ config = MkdocsNoteConfig ()
198+ remover = NoteRemover (config )
199+
200+ # Remove the note
201+ result = remover .remove_note (note_path , remove_assets = not keep_assets )
202+
203+ if result .success :
204+ click .echo (f"✅ { result .message } " )
205+ if result .data ["removed_assets" ]:
206+ click .echo (f"📁 Removed assets: { result .data ['asset_dir' ]} " )
207+ else :
208+ click .echo (f"📁 Kept assets: { result .data ['asset_dir' ]} " )
209+ sys .exit (0 )
210+ else :
211+ click .echo (f"❌ Error: { result .message } " , err = True )
212+ sys .exit (1 )
213+
214+ except Exception as e :
215+ click .echo (f"❌ Unexpected error: { e } " , err = True )
216+ sys .exit (1 )
138217
139218
140219@cli .command ("rm" )
141- @click .argument ("file_path" , required = False )
220+ @click .argument ("file_path" , required = True )
221+ @click .option ("--keep-assets" , is_flag = True , help = "Keep the asset directory" )
222+ @click .option ("--yes" , "-y" , is_flag = True , help = "Skip confirmation" )
142223@click .pass_context
143- def rm_command (ctx , file_path ):
224+ def rm_command (ctx , file_path , keep_assets , yes ):
144225 """Alias for 'remove' command - Remove a note file and its asset directory."""
145- ctx .invoke (remove_command , file_path = file_path )
226+ ctx .invoke (remove_command , file_path = file_path , keep_assets = keep_assets , yes = yes )
146227
147228
148229@cli .command ("move" )
149- @click .argument ("source" , required = False )
150- @click .argument ("destination" , required = False )
230+ @click .argument ("source" , required = True )
231+ @click .argument ("destination" , required = True )
232+ @click .option (
233+ "--keep-source-assets" ,
234+ is_flag = True ,
235+ help = "Keep the source asset directory (don't move it)" ,
236+ )
237+ @click .option (
238+ "--yes" ,
239+ "-y" ,
240+ is_flag = True ,
241+ help = "Skip confirmation prompt" ,
242+ )
151243@click .pass_context
152- def move_command (ctx , source , destination ):
244+ def move_command (ctx , source , destination , keep_source_assets , yes ):
153245 """Move or rename a note file/directory and its asset directory.
154246
155247 \b
@@ -159,58 +251,146 @@ def move_command(ctx, source, destination):
159251 Examples:
160252 mkdocs-note move docs/notes/old.md docs/notes/new.md
161253 mkdocs-note mv docs/notes/test.md docs/notes/archive
254+ mkdocs-note move docs/notes/drafts docs/notes/published --yes
162255
163256 \b
164257 Arguments:
165258 SOURCE: Current path of the note file or directory
166259 DESTINATION: Destination path (or parent directory if exists)
167260 """
168- click .echo ("⚠️ 'move' command is not yet implemented" )
169- click .echo ("💡 This feature is being refactored" )
170- sys .exit (1 )
261+ try :
262+ source_path = Path (source )
263+ dest_path = Path (destination )
264+
265+ # Check if source exists
266+ if not source_path .exists ():
267+ click .echo (f"❌ Error: Source does not exist: { source_path } " , err = True )
268+ sys .exit (1 )
269+
270+ # Confirmation prompt (unless --yes)
271+ if not yes :
272+ asset_msg = "with assets" if not keep_source_assets else "(keeping assets)"
273+ if not click .confirm (f"Move { source_path } → { dest_path } { asset_msg } ?" ):
274+ click .echo ("⚠️ Cancelled" )
275+ sys .exit (0 )
276+
277+ # Load configuration
278+ config = MkdocsNoteConfig ()
279+ mover = NoteMover (config )
280+
281+ # Move the note or directory
282+ result = mover .move_note_or_directory (
283+ source_path , dest_path , move_assets = not keep_source_assets
284+ )
285+
286+ if result .success :
287+ click .echo (f"✅ { result .message } " )
288+ if "source" in result .data and "destination" in result .data :
289+ click .echo (f"📝 From: { result .data ['source' ]} " )
290+ click .echo (f"📝 To: { result .data ['destination' ]} " )
291+ if "asset_moved" in result .data :
292+ if result .data ["asset_moved" ]:
293+ click .echo ("📁 Assets moved" )
294+ else :
295+ click .echo ("📁 Assets kept at source" )
296+ sys .exit (0 )
297+ else :
298+ click .echo (f"❌ Error: { result .message } " , err = True )
299+ sys .exit (1 )
300+
301+ except Exception as e :
302+ click .echo (f"❌ Unexpected error: { e } " , err = True )
303+ sys .exit (1 )
171304
172305
173306@cli .command ("mv" )
174- @click .argument ("source" , required = False )
175- @click .argument ("destination" , required = False )
307+ @click .argument ("source" , required = True )
308+ @click .argument ("destination" , required = True )
309+ @click .option ("--keep-source-assets" , is_flag = True , help = "Keep source assets" )
310+ @click .option ("--yes" , "-y" , is_flag = True , help = "Skip confirmation" )
176311@click .pass_context
177- def mv_command (ctx , source , destination ):
312+ def mv_command (ctx , source , destination , keep_source_assets , yes ):
178313 """Alias for 'move' command - Move or rename a note file/directory and its assets."""
179- ctx .invoke (move_command , source = source , destination = destination )
314+ ctx .invoke (
315+ move_command ,
316+ source = source ,
317+ destination = destination ,
318+ keep_source_assets = keep_source_assets ,
319+ yes = yes ,
320+ )
180321
181322
182323@cli .command ("clean" )
324+ @click .option (
325+ "--dry-run" ,
326+ is_flag = True ,
327+ help = "Show what would be removed without actually removing" ,
328+ )
329+ @click .option (
330+ "--yes" ,
331+ "-y" ,
332+ is_flag = True ,
333+ help = "Skip confirmation prompt" ,
334+ )
183335@click .pass_context
184- def clean_command (ctx ):
336+ def clean_command (ctx , dry_run , yes ):
185337 """Clean up orphaned asset directories without corresponding notes.
186338
187339 \b
188340 Examples:
189341 mkdocs-note clean --dry-run
190342 mkdocs-note clean --yes
343+ mkdocs-note clean
191344 """
192- click .echo ("⚠️ 'clean' command is not yet implemented" )
193- click .echo ("💡 This feature is being refactored" )
194- sys .exit (1 )
195-
196-
197- @cli .command ("template" )
198- @click .pass_context
199- def template_command (ctx ):
200- """Manage the note template file.
201-
202- This command helps you check and create the template file
203- configured in your mkdocs.yml.
204-
205- \b
206- Examples:
207- mkdocs-note template
208- mkdocs-note template --check
209- mkdocs-note template --create
210- """
211- click .echo ("⚠️ 'template' command is not yet implemented" )
212- click .echo ("💡 This feature is being refactored" )
213- sys .exit (1 )
345+ try :
346+ # Load configuration
347+ config = MkdocsNoteConfig ()
348+ cleaner = NoteCleaner (config )
349+
350+ # Find orphaned assets
351+ if dry_run :
352+ click .echo ("🔍 Scanning for orphaned assets (dry run mode)..." )
353+ else :
354+ click .echo ("🔍 Scanning for orphaned assets..." )
355+
356+ result = cleaner .clean_orphaned_assets (dry_run = True )
357+
358+ if result .data ["removed_count" ] == 0 :
359+ click .echo ("✅ No orphaned asset directories found" )
360+ sys .exit (0 )
361+
362+ # Show what will be removed
363+ click .echo (
364+ f"\n { 'Would remove' if dry_run else 'Found' } { result .data ['removed_count' ]} orphaned asset director{ 'y' if result .data ['removed_count' ] == 1 else 'ies' } :"
365+ )
366+ for orphaned_dir in result .data ["orphaned_dirs" ]:
367+ click .echo (f" 📁 { orphaned_dir } " )
368+
369+ # If dry run, exit here
370+ if dry_run :
371+ click .echo ("\n 💡 Run without --dry-run to actually remove these directories" )
372+ sys .exit (0 )
373+
374+ # Confirmation prompt (unless --yes)
375+ if not yes :
376+ if not click .confirm (f"\n Remove these { result .data ['removed_count' ]} directories?" ):
377+ click .echo ("⚠️ Cancelled" )
378+ sys .exit (0 )
379+
380+ # Actually clean
381+ click .echo ("\n 🗑️ Removing orphaned assets..." )
382+ result = cleaner .clean_orphaned_assets (dry_run = False )
383+
384+ if result .success :
385+ click .echo (f"✅ { result .message } " )
386+ sys .exit (0 )
387+ else :
388+ click .echo (f"❌ Error: { result .message } " , err = True )
389+ sys .exit (1 )
390+
391+ except Exception as e :
392+ click .echo (f"❌ Unexpected error: { e } " , err = True )
393+ sys .exit (1 )
214394
215395
216396if __name__ == "__main__" :
0 commit comments