All files / commands edit-notebook-cell-slug.ts

0% Statements 0/41
0% Branches 0/28
0% Functions 0/4
0% Lines 0/41

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104                                                                                                                                                                                                               
import * as vscode from 'vscode';
import { container } from 'tsyringe';
import { ServiceToken } from '@src/services/tokens';
import { DocumentContextService } from '@src/services/document/document-context-service';
import { ReferenceUpdateService } from '@src/services/core/reference-update-service';
import { WorkspaceUri } from '@src/providers/workspace-uri';
import { findNotebookContainingCell } from '@src/utilities/vscode/notebook';
 
/**
 * A regular expression that validates a notebook cell slug.
 * Must match the SLUG_PATTERN in notebook-serializer.ts.
 */
const SLUG_PATTERN = /^[a-z0-9][a-z0-9-]*$/;
 
export const editNotebookCellSlug = {
	id: 'mentor.command.editNotebookCellSlug',
	handler: async (cellDocumentUri: vscode.Uri) => {
		if (!cellDocumentUri) {
			vscode.window.showWarningMessage('No notebook cell specified.');
			return;
		}
 
		// Find the notebook that contains this cell.
		const notebook = findNotebookContainingCell(cellDocumentUri);
 
		if (!notebook) {
			vscode.window.showWarningMessage('Could not find the notebook containing this cell.');
			return;
		}
 
		const cell = notebook.getCells().find(
			c => c.document.uri.toString() === cellDocumentUri.toString()
		);
 
		if (!cell) {
			vscode.window.showWarningMessage('Could not find the notebook cell.');
			return;
		}
 
		const contextService = container.resolve<DocumentContextService>(ServiceToken.DocumentContextService);
		const ctx = contextService.contexts[cellDocumentUri.toString()];
		const currentSlug: string = cell.metadata?.slug ?? ctx?.slug ?? '';
 
		const newSlug = await vscode.window.showInputBox({
			title: 'Edit Cell Slug',
			prompt: 'Enter a human-readable identifier for this cell (used as the graph URI fragment).',
			value: currentSlug,
			placeHolder: 'e.g. my-data',
			validateInput: (value) => {
				if (!value) {
					return 'Slug cannot be empty.';
				}
 
				if (!SLUG_PATTERN.test(value)) {
					return 'Slug must start with a lowercase letter or digit and may only contain lowercase letters, digits, and hyphens.';
				}
 
				// Check for uniqueness among other cells in the same notebook.
				const isDuplicate = notebook.getCells().some(
					c => c.index !== cell.index && c.metadata?.slug === value
				);
 
				if (isDuplicate) {
					return `The slug "${value}" is already used by another cell in this notebook.`;
				}
 
				return undefined;
			}
		});
 
		if (!newSlug || newSlug === currentSlug) {
			return;
		}
 
		// Compute the old and new workspace IRIs for the reference update.
		const oldIri = WorkspaceUri.toWorkspaceUri(cellDocumentUri, currentSlug)?.toString();
		const newIri = WorkspaceUri.toWorkspaceUri(cellDocumentUri, newSlug)?.toString();
 
		// Update the cell metadata in the notebook document.
		const newMetadata = { ...cell.metadata, slug: newSlug, slugIsAuto: false };
		const notebookEdit = vscode.NotebookEdit.updateCellMetadata(cell.index, newMetadata);
		const workspaceEdit = new vscode.WorkspaceEdit();
		workspaceEdit.set(notebook.uri, [notebookEdit]);
 
		await vscode.workspace.applyEdit(workspaceEdit);
 
		// Update the document context slug immediately so CodeLens and graphIri reflect
		// the new slug without waiting for re-indexing.
		if (ctx) {
			ctx.slug = newSlug;
		}
 
		// Update all workspace: URI references across the workspace.
		if (oldIri && newIri && oldIri !== newIri) {
			const referenceService = container.resolve<ReferenceUpdateService>(ServiceToken.ReferenceUpdateService);
			
			await referenceService.batchUpdate(
				new Map([[oldIri, newIri]]),
				cellDocumentUri
			);
		}
	}
};