Skip to content

Commit e04a63c

Browse files
enhance: differentiate permalink rename and file movement of mv cli
1 parent 2a6dd48 commit e04a63c

5 files changed

Lines changed: 568 additions & 52 deletions

File tree

docs/usage/cli.md

Lines changed: 72 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
date: 2026-01-10 22:09:00
2+
date: 2026-01-10 23:40:00
33
title: Command Line Interface
44
permalink:
55
publish: true
@@ -131,7 +131,13 @@ Remove a note file and its corresponding asset directory.
131131
132132
### `move`
133133
134-
Move or rename a note file/directory and its corresponding asset directory.
134+
Move or rename a note file/directory and its corresponding asset directory, or rename permalink value.
135+
136+
The `move` command supports two modes:
137+
138+
#### File Move Mode (default)
139+
140+
Move or rename a note file/directory and its corresponding asset directory. The permalink value remains unchanged, and asset directories are moved based on their permalink.
135141
136142
- **Usage:**
137143
@@ -144,18 +150,24 @@ Move or rename a note file/directory and its corresponding asset directory.
144150
145151
- `SOURCE` (required): Current path of the note file or directory
146152
147-
- `DESTINATION` (required): Destination path
153+
- `DESTINATION` (required): Destination path (or parent directory if exists)
148154
149155
- **Options:**
150156
151-
- `--keep-source-assets`: Keep the source asset directory (don't move it)
157+
- `--keep-source-assets`: Keep the source asset directory (don't move it) [NOT IMPLEMENTED]
152158

153159
- `--yes, -y`: Skip confirmation prompt
154160

155161
- **Features:**
156162

157163
- Moves both the note file and its corresponding asset directory by default
158164

165+
- Asset directories are identified by permalink, not filename
166+
167+
- If moving to a different directory, asset directory moves with the note
168+
169+
- If only renaming the file within the same directory, asset directory stays in place (based on permalink)
170+
159171
- Supports moving single files or entire directories
160172

161173
- Automatically creates necessary parent directories
@@ -171,17 +183,14 @@ Move or rename a note file/directory and its corresponding asset directory.
171183
- **Examples:**
172184

173185
```bash
174-
# Rename a note
186+
# Rename a note file (same directory, asset directory stays in place)
175187
mkdocs-note move docs/notes/old-name.md docs/notes/new-name.md
176188
177-
# Move to different directory
189+
# Move to different directory (asset directory moves with note)
178190
mkdocs-note mv docs/notes/draft.md docs/notes/published/
179191
180192
# Move entire directory
181193
mkdocs-note move docs/notes/drafts docs/notes/published --yes
182-
183-
# Move without moving assets
184-
mkdocs-note mv docs/notes/test.md docs/archive/test.md --keep-source-assets
185194
```
186195

187196
- **Output:**
@@ -193,6 +202,60 @@ Move or rename a note file/directory and its corresponding asset directory.
193202
📁 Assets moved
194203
```
195204

205+
#### Permalink Rename Mode
206+
207+
Rename the permalink value in frontmatter and the asset directory name. The file location remains unchanged.
208+
209+
- **Usage:**
210+
211+
```bash
212+
mkdocs-note move SOURCE -p PERMALINK [OPTIONS]
213+
mkdocs-note mv SOURCE --permalink PERMALINK [OPTIONS] # Alias
214+
```
215+
216+
- **Arguments:**
217+
218+
- `SOURCE` (required): Path to the note file (must be a file, not a directory)
219+
220+
- `DESTINATION`: Ignored in permalink rename mode
221+
222+
- **Options:**
223+
224+
- `--permalink, -p` (required): New permalink value
225+
226+
- `--yes, -y`: Skip confirmation prompt
227+
228+
- **Features:**
229+
230+
- Updates the permalink value in the note file's frontmatter
231+
232+
- Renames the asset directory based on the new permalink value
233+
234+
- File location remains unchanged
235+
236+
- Only works on single files, not directories
237+
238+
- Prompts for confirmation before renaming (unless `--yes` is used)
239+
240+
- **Examples:**
241+
242+
```bash
243+
# Rename permalink and asset directory
244+
mkdocs-note move docs/notes/my-note.md -p new-permalink-slug
245+
246+
# Rename permalink without confirmation
247+
mkdocs-note mv docs/notes/test.md --permalink updated-slug --yes
248+
```
249+
250+
- **Output:**
251+
252+
```
253+
✅ Successfully renamed permalink
254+
📝 File: docs/notes/my-note.md
255+
🔗 Permalink: old-permalink → new-permalink-slug
256+
📁 Asset directory renamed
257+
```
258+
196259
### `clean`
197260
198261
Clean up orphaned asset directories without corresponding notes.

src/mkdocs_note/cli.py

Lines changed: 134 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -279,11 +279,16 @@ def rm_command(ctx, file_path, keep_assets, yes):
279279

280280
@cli.command("move")
281281
@click.argument("source", required=True)
282-
@click.argument("destination", required=True)
282+
@click.argument("destination", required=False)
283+
@click.option(
284+
"--permalink",
285+
"-p",
286+
help="Rename permalink value and asset directory name (destination argument is ignored in this mode)",
287+
)
283288
@click.option(
284289
"--keep-source-assets",
285290
is_flag=True,
286-
help="Keep the source asset directory (don't move it)",
291+
help="Keep the source asset directory (don't move it) [NOT IMPLEMENTED]",
287292
)
288293
@click.option(
289294
"--yes",
@@ -292,60 +297,151 @@ def rm_command(ctx, file_path, keep_assets, yes):
292297
help="Skip confirmation prompt",
293298
)
294299
@click.pass_context
295-
def move_command(ctx, source, destination, keep_source_assets, yes):
296-
"""Move or rename a note file/directory and its asset directory.
300+
def move_command(ctx, source, destination, permalink, keep_source_assets, yes):
301+
"""Move or rename a note file/directory and its asset directory, or rename permalink.
297302
298303
\b
299304
Aliases: mv
300305
306+
\b
307+
File Move Mode (default):
308+
Move or rename a note file/directory and its asset directory.
309+
301310
\b
302311
Examples:
312+
# Move/rename file
303313
mkdocs-note move docs/notes/old.md docs/notes/new.md
304314
mkdocs-note mv docs/notes/test.md docs/notes/archive
315+
316+
# Move entire directory
305317
mkdocs-note move docs/notes/drafts docs/notes/published --yes
306318
319+
\b
320+
Permalink Rename Mode (use -p/--permalink):
321+
Rename permalink value in frontmatter and asset directory name.
322+
323+
\b
324+
Examples:
325+
mkdocs-note move docs/notes/my-note.md -p new-permalink
326+
mkdocs-note mv docs/notes/test.md --permalink updated-slug
327+
307328
\b
308329
Arguments:
309-
SOURCE: Current path of the note file or directory
310-
DESTINATION: Destination path (or parent directory if exists)
330+
SOURCE: Current path of the note file or directory (or file path for permalink mode)
331+
DESTINATION: Destination path (or parent directory if exists). Ignored if --permalink is used.
311332
"""
312333
try:
313334
# Load configuration and setup environment
314335
config = MkdocsNoteConfig()
315336
setup_cli_environment(config)
316337

317338
source_path = Path(source)
318-
dest_path = Path(destination)
319339

320340
# Check if source exists
321341
if not source_path.exists():
322342
click.echo(f"❌ Error: Source does not exist: {source_path}", err=True)
323343
sys.exit(1)
324344

325-
# Confirmation prompt (unless --yes)
326-
if not yes:
327-
asset_msg = "with assets" if not keep_source_assets else "(keeping assets)"
328-
if not click.confirm(f"Move {source_path}{dest_path} {asset_msg}?"):
329-
click.echo("⚠️ Cancelled")
330-
sys.exit(0)
331-
332-
# Move the note using MoveCommand
333-
# Note: Current MoveCommand doesn't have keep_source_assets parameter
334-
# It always moves assets, so we need to handle this limitation
335-
command = MoveCommand()
336-
command.execute(source_path, dest_path)
337-
338-
# Check if move was successful
339-
if dest_path.exists() and not source_path.exists():
340-
click.echo("✅ Successfully moved")
341-
click.echo(f"📝 From: {source_path}")
342-
click.echo(f"📝 To: {dest_path}")
343-
if not keep_source_assets:
344-
click.echo("📁 Assets moved")
345-
else:
346-
click.echo("📁 Assets kept at source")
345+
# Permalink rename mode
346+
if permalink:
347+
if not source_path.is_file():
348+
click.echo(
349+
f"❌ Error: Permalink rename only works on files, not directories: {source_path}",
350+
err=True,
351+
)
352+
sys.exit(1)
353+
354+
# Get current permalink for confirmation message
355+
current_permalink = cli_common.get_permalink_from_file(source_path)
356+
357+
# Confirmation prompt (unless --yes)
358+
if not yes:
359+
current_msg = (
360+
f"'{current_permalink}'" if current_permalink else "(none)"
361+
)
362+
if not click.confirm(
363+
f"Rename permalink in {source_path} from {current_msg} to '{permalink}'?"
364+
):
365+
click.echo("⚠️ Cancelled")
366+
sys.exit(0)
367+
368+
# Rename permalink using MoveCommand
369+
command = MoveCommand()
370+
command.execute(source_path, destination=None, permalink=permalink)
371+
372+
click.echo("✅ Successfully renamed permalink")
373+
click.echo(f"📝 File: {source_path}")
374+
click.echo(f"🔗 Permalink: {current_permalink or '(none)'}{permalink}")
375+
click.echo("📁 Asset directory renamed")
347376
sys.exit(0)
377+
378+
# File move mode (original behavior)
348379
else:
380+
if destination is None:
381+
click.echo(
382+
"❌ Error: DESTINATION is required in file move mode", err=True
383+
)
384+
sys.exit(1)
385+
386+
dest_path = Path(destination)
387+
388+
# Confirmation prompt (unless --yes)
389+
if not yes:
390+
asset_msg = (
391+
"with assets" if not keep_source_assets else "(keeping assets)"
392+
)
393+
if not click.confirm(f"Move {source_path}{dest_path} {asset_msg}?"):
394+
click.echo("⚠️ Cancelled")
395+
sys.exit(0)
396+
397+
# Save source type before move (since source_path won't exist after move)
398+
is_source_file = source_path.is_file()
399+
is_source_dir = source_path.is_dir()
400+
source_name = source_path.name
401+
402+
# Move the note using MoveCommand
403+
# Note: Current MoveCommand doesn't have keep_source_assets parameter
404+
# It always moves assets, so we need to handle this limitation
405+
command = MoveCommand()
406+
command.execute(source_path, dest_path)
407+
408+
# Check if move was successful
409+
# For directory destinations, check if file exists in destination
410+
if is_source_file:
411+
# Determine final destination path
412+
if dest_path.exists() and dest_path.is_dir():
413+
# File moved into directory
414+
final_dest = dest_path / source_name
415+
else:
416+
# File moved/renamed to dest_path
417+
final_dest = dest_path
418+
419+
# Check if move was successful
420+
if final_dest.exists() and not source_path.exists():
421+
click.echo("✅ Successfully moved")
422+
click.echo(f"📝 From: {source_path}")
423+
click.echo(f"📝 To: {final_dest}")
424+
if not keep_source_assets:
425+
click.echo("📁 Assets moved")
426+
else:
427+
click.echo("📁 Assets kept at source")
428+
sys.exit(0)
429+
elif is_source_dir:
430+
# Directory move - check if destination directory exists
431+
if (
432+
dest_path.exists()
433+
and dest_path.is_dir()
434+
and not source_path.exists()
435+
):
436+
click.echo("✅ Successfully moved")
437+
click.echo(f"📝 From: {source_path}")
438+
click.echo(f"📝 To: {dest_path}")
439+
if not keep_source_assets:
440+
click.echo("📁 Assets moved")
441+
else:
442+
click.echo("📁 Assets kept at source")
443+
sys.exit(0)
444+
349445
click.echo("❌ Error: Failed to move note", err=True)
350446
sys.exit(1)
351447

@@ -356,16 +452,22 @@ def move_command(ctx, source, destination, keep_source_assets, yes):
356452

357453
@cli.command("mv")
358454
@click.argument("source", required=True)
359-
@click.argument("destination", required=True)
360-
@click.option("--keep-source-assets", is_flag=True, help="Keep source assets")
455+
@click.argument("destination", required=False)
456+
@click.option(
457+
"--permalink", "-p", help="Rename permalink value and asset directory name"
458+
)
459+
@click.option(
460+
"--keep-source-assets", is_flag=True, help="Keep source assets [NOT IMPLEMENTED]"
461+
)
361462
@click.option("--yes", "-y", is_flag=True, help="Skip confirmation")
362463
@click.pass_context
363-
def mv_command(ctx, source, destination, keep_source_assets, yes):
464+
def mv_command(ctx, source, destination, permalink, keep_source_assets, yes):
364465
"""Alias for 'move' command - Move or rename a note file/directory and its assets."""
365466
ctx.invoke(
366467
move_command,
367468
source=source,
368469
destination=destination,
470+
permalink=permalink,
369471
keep_source_assets=keep_source_assets,
370472
yes=yes,
371473
)

0 commit comments

Comments
 (0)