Add a command : Move current file’s folder to another folder

Hi,

There is another solution posted in this forum using templater but it didn’t work as intended. I think templater is not the right tool for this kind of job anyway. Hence, here is my solution.

Requirement

Steps

  • Create a script file named move folder to.js in the user plugin path you set in the plugin. For instance: MyScripts/UserPlugins
  • Add this code into move folder to.js
module.exports = {};
const { Plugin, Notice, SuggestModal } = require("obsidian");

// Custom SuggestModal for selecting folders.
class FolderSuggester extends SuggestModal {
	constructor(app, folders, onChoose) {
		super(app);
		this.folders = folders;
		this.onChoose = onChoose;
		this.setPlaceholder("Select a destination folder");
		this.titleEl.setText("Move Folder to...");
	}

	// Filters folders based on user input.
	getSuggestions(query) {
		return this.folders.filter((folder) =>
			folder.path.toLowerCase().includes(query.toLowerCase()),
		);
	}

	// Renders each folder suggestion in the list.
	renderSuggestion(folder, el) {
		el.createEl("div", { text: folder.path });
	}

	// Called when a folder is selected.
	onChooseSuggestion(folder, evt) {
		this.onChoose(folder);
	}
}

// Main plugin class.
module.exports.default = class MyPlugin extends Plugin {
	async onload() {
		// Adds a command to move the current folder.
		this.addCommand({
			id: "move-current-folder",
			name: "Move current file’s folder to another folder",
			callback: async () => {
				// Gets all loaded files in the vault.
				const allFiles = this.app.vault.getAllLoadedFiles();

				// Filters only the folders.
				const folders = allFiles.filter((file) => {
					if (file.path) {
						const abstractFile = this.app.vault.getAbstractFileByPath(
							file.path,
						);
						return abstractFile && abstractFile.hasOwnProperty("children"); // Check if the abstractFile has children, indicating it is a folder.
					}
					return false;
				});

				// Opens the FolderSuggester to select the destination folder.
				new FolderSuggester(this.app, folders, async (selectedFolder) => {
					// Gets the current file’s title for debugging
					const currentFileTitle = this.app.workspace.getActiveFile().name;

					// Gets the path of the current file's parent folder.
					const currentFolderPath =
						this.app.workspace.getActiveFile().parent.path;

					console.log(
						`current file path: ${currentFolderPath}/${currentFileTitle}`,
					);

					if (currentFolderPath === "/") {
						// Check if the current folder is the root of the vault.
						// Display an error message and exit if it is.
						new Notice("Cannot move the root folder.", 3000);
						return;
					}

					// Gets the TFolder object of the current folder.
					const currentFolder =
						this.app.vault.getAbstractFileByPath(currentFolderPath);

					if (currentFolder && selectedFolder) {
						// Checks if both the current and selected folders exist.
						// Constructs the new path for the folder.
						const newFolderPath = `${selectedFolder.path}/${currentFolder.name}`;
						// Renames (moves) the folder to the new path.
						await this.app.vault.rename(currentFolder, newFolderPath);
						// Displays a success notification.
						new Notice(
							`Successfully moved ${currentFolder.name} to ${selectedFolder.name}`,
							2800,
						);
					}
				}).open();
			},
		});
	}
};

Now you can use this command via the palette or add a hotkey.

Enjoy !


P.S.: If you want to convert this script to use it via another plugin, please share below and I will update this post for the people who already use this other plugin instead of user plugins.

1 Like