EmEditorみんなでまとめサイト

リスト置換マクロ(メニュー版)

最終更新:

匿名ユーザー

- view
だれでも歓迎! 編集

概要

リストで置換マクロの姉妹品です。メニューから置換リストを選ぶ事ができます。無駄に高機能です。

詳しくは、付属の readme.txt をご覧下さい。

ダウンロード

コメント

  • ご意見・ご感想・ご要望 何かあればどぞー -- Nanasiya
  • Dmonkyに移植するのは困難でしょうか? VxEditorで使いたいのですが。 --
    名前:
    コメント:

コード

/*
 *	リスト置換マクロ for EmEditor   version 0.02
 *	Created by Nanasiya
 *
 *	改造・再配布等、ご自由にご利用ください。
 */

/*	[Changelog]
 *
 *	version 0.02
 *		- 置換オプションを書くとエラーが出てしまったのを修正。
 *		- サンプルファイルを付けた。
 *
 *	version 0.01
 *		- 公開。
 *
 */

/*** 設定ここから ***/

// Windows XP なら 1 それ以前の Windows なら 0
var winxp = 1;

//「置換リストファイル」のリスト
var replaceFileListName = "repfiles.txt";

// 置換オプションデフォルト
var replaceOption =
	//	eeFindReplaceCase          |    // 大文字小文字を区別
	//	eeFindReplaceEscSeq        |    // エスケープシーケンス使用
		eeFindReplaceQuiet         |    // メッセージ表示なし
	//	eeFindReplaceOnlyWord      |    // 単語のみ
		eeFindReplaceRegExp        |    // 正規表現
	//	eeReplaceSelOnly           |    // 選択範囲のみ置換
		eeReplaceAll               |    // すべて置換
		0;

// フォルダを置換する際のフィルタ関数 (true なら置換する)
var isReplacableFile = function (fileName) {
	return true;                                       // 常に置換する
//	return fileName.match(/\.txt$/);                   // 拡張子 .txt のファイルだけ置換
//  return fileName.match(/\.(c|h|cpp|hpp)$/);         // 拡張子 .c .h .cpp .hpp を置換
}
// サブフォルダも置換対象にするかどうかデフォルト ( 0 = しない / 1 = する )
var searchInSubFolder = 0;

// 置換後、自動的に保存するかどうかデフォルト ( 0 = しない / 1 = する )
var autoSaveAfterReplace = 1;
// バックアップするかどうかデフォルト ( 0 = しない / 1 = する )
var backup = 1;
// バックアップする場合のファイル名生成関数
var backupFileName = function (fileName) {
	if (!fileName) return "";                          // 無名ならバックアップしない
	return fileName + ".bak";                          // file.txt.bak
//	return fileName.replace(/\..+?$/, ".bak");         // file.bak
//	return fileName.replace(/\\(.+?)$/, "\\bak\\$1");  // bak\file.txt
};

/*** 設定ここまで ***/

var FSO   = new ActiveXObject("Scripting.FileSystemObject");
var SHELL = new ActiveXObject("WScript.Shell");
SHELL.CurrentDirectory = FSO.GetParentFolderName(ScriptFullName);

var target = document;
var targetIsFile = true;

var replaceFileList = openReplaceFileList();
var replaceFile = "";
var menuItemInfo = { };


//--- メインメニュー ---

var mainMenu;
while(true) {
	mainMenu = buildMainMenu();
	var result = mainMenu.Track(0);
	if (result == 0) break;

	if (result == 1) {             // 置換リストファイルを選択
		var file = openFileDialog();
		if (file) {
			replaceFile = file;
			break;
		}
	}
	else if (result < 1000) {      // 置換リスト選択
		replaceFile = menuItemInfo["id" + result];
		break;
	}
	else if (result == 1000) {     // 置換対象 : このドキュメント
		target = document;
		targetIsFile = true;
	}
	else if (result < 1500) {      // 置換対象 : 開いているドキュメント
		target = menuItemInfo["id" + result];
		targetIsFile = true;
	}
	else if (result == 1500) {     // 置換対象 : ファイルを選択
		var file = openFileDialog();
		if (file) {
			target = file;
			targetIsFile = true;
		}
	}
	else if (result == 1501) {     // 置換対象 : フォルダを選択
		var folder = openFolderDialog();
		if (folder) {
			target = folder;
			targetIsFile = false;
		}
	}
	else if (result == 1502) {     // 置換対象 : サブフォルダも置換対象にする
		searchInSubFolder = !searchInSubFolder;
	}
	else if (result == 2000) {     // 自動保存
		autoSaveAfterReplace = !autoSaveAfterReplace;
	}
	else if (result == 2001) {     // バックアップ
		backup = !backup;
	}
}

if (!target || !replaceFile) {   // キャンセルされた
	Quit();
}


//--- 置換実行 ---

// 置換リストを読み込み
var replaceList = openReplaceList();
if (!replaceList || replaceList.length == 0) {
	alert("置換リストが無効です");
	Quit();
}

// 置換を実行
doReplace();

alert("置換が完了しました");


//--- 関数 ---

// 置換ファイルリストを読み込んで返す
function openReplaceFileList() {
	if (!FSO.FileExists(replaceFileListName)) return [];

	var f = FSO.OpenTextFile(replaceFileListName, 1);
	return readReplaceListFile(f);
}

// ファイルから読み込みつつ置換ファイルリストを作成
function readReplaceListFile(f) {
	var list = [];

	while(!f.AtEndOfStream) {
		var line = f.ReadLine();
		if (line.match(/^\s*$/)) {                // 空行
			continue;
		}
		else if (line.match(/^\s*\[(.*)\s*$/)) {  // サブメニュー開始
			// 再帰的に自身を呼び出して作成
			var caption = RegExp.$1 ? RegExp.$1 : "sub menu";
			var item = readReplaceListFile(f);
			if (item && item.length > 0) {
				list.push({ submenu: true, caption: caption, item: item });
			}
		}
		else if (line.match(/^\s*\]\s*$/)) {      // サブメニュー終了
			break;
		}
		else if (line.match(/^\s*-+\s*$/)) {      // セパレータ
			list.push({ submenu: false, caption: "-", item: "-" });
		}
		else if (line.match(/^\s*((.+?)\t+)?(.+?)\s*$/)) {  // ファイル
			// "A\tB" なら A が項目名 B がファイル名
			// "A" だけなら A がファイル名 とする
			var caption = RegExp.$2 || FSO.GetFileName(RegExp.$3);
			list.push({ submenu: false,
				        caption: caption,
				        item: RegExp.$3 });
		}
	}

	return list;
}

// 置換リストを読み込む
function openReplaceList() {
	var doc = document;
	var num = editor.Documents.Count;

	editor.OpenFile(replaceFile, 0, eeOpenAllowNewWindow);
	document.selection.SelectAll();
	var text = document.selection.Text;

	var list = [ ];
	if (text) {
		text = text.split(/\r\n|\r|\n/);
		for (var i in text) {
			if (text[i].match(/^([^\t]*)\t([^\t]*)(\t([^\t]+))?$/)) {
				list.push({
					find: RegExp.$1,
					replace: RegExp.$2,
					option: parseOption(RegExp.$4)
				});
			}
		}
	}

	if (num < editor.Documents.Count) document.close();
	doc.Activate();
	return list;
}

// 置換オプションのパース
function parseOption(opt) {
	var option = replaceOption;
	if (!opt) return option;

	var p = true;
	for(var i = 0; i < opt.length; i++) {
		switch(opt.charAt(i).toLowerCase()) {
			case '+': p = true;  break;
			case '-': p = false; break;
			case 'i': setSwitch(option, eeFindReplaceCase, p); break;
			case 'e': setSwitch(option, eeFindReplaceEscSeq, p); break;
			case 'q': setSwitch(option, eeFindReplaceQuiet, p); break;
			case 'w': setSwitch(option, eeFindReplaceOnlyWord, p); break;
			case 'x': setSwitch(option, eeFindReplaceRegExp, p); break;
			case 's': setSwitch(option, eeReplaceSelOnly, p); break;
			case 'a': setSwitch(option, eeReplaceAll, p); break;
		}
	}
	return option;
}

// オプションスイッチのON/OFF
function setSwitch(option, sw, swon) {
	if (swon) {
		return option | sw;
	} else {
		return option & (~sw);
	}
}

// 置換を実行
function doReplace() {
	var lastDocument = document;

	if (targetIsFile) {
		if (typeof(target) == "string") {
			// ファイルパスの場合
			doReplaceInFile(target);
		} else {
			// ドキュメントオブジェクトの場合
			doReplaceInDocument(target);
		}
	} else {
		// フォルダの場合
		doReplaceInFolder(target);
	}

	lastDocument.Activate();
}

// ファイルを開いてから置換を実行
function doReplaceInFile(path) {
	var num = editor.Documents.Count;
	editor.OpenFile(path, 0, eeOpenAllowNewWindow);
	doReplaceInDocument(document);
	if (num < editor.Documents.Count) document.close();
}

// フォルダ置換を実行
function doReplaceInFolder(path) {
	var folder = FSO.GetFolder(path);
	var files = new Enumerator(folder.Files);
	for ( ; !files.atEnd(); files.moveNext()) {
		var fileName = files.item().Path;
		if (isReplacableFile(fileName)) {
			// 置換対象なら
			doReplaceInFile(fileName);
		}
	}

	if (searchInSubFolder) {
		// サブフォルダも置換対象にする場合
		var subs = new Enumerator(folder.SubFolders);
		for ( ; !subs.atEnd(); subs.moveNext()) {
			doReplaceInFolder(subs.item().Path);
		}
	}
}

// ドキュメントを置換
function doReplaceInDocument(doc) {
	doc.Activate();
	if (backup) backupDocument(doc);

	for (var i in replaceList) {
		var item = replaceList[i];
		doc.selection.Replace(item.find, item.replace, item.option);
	}
	doc.HighlightFind = false;

	if (autoSaveAfterReplace) {
		doc.Save(doc.FullName);
	}
}

// ドキュメントのバックアップを作成
function backupDocument(doc) {
	var fileName = backupFileName(doc.FullName);
	if (!fileName) return;

	// 親フォルダが存在しなければ作成する
	var folderName = FSO.GetParentFolderName(fileName);
	if (!FSO.FolderExists(folderName)) {
		SHELL.Run("cmd /c md \"" + folderName + "\"", 0, true);
	}

	var sel = saveSelection(doc.selection);
	doc.selection.SelectAll();
	var text = doc.selection.Text;

	editor.NewFile();
	document.ConfigName = doc.ConfigName;
	document.Encoding = doc.Encoding;
	document.UnicodeSignature = doc.UnicodeSignature;
	document.writeln(text);
	document.Save(fileName);
	document.close();

	restoreSelection(doc.selection, sel);
	doc.Activate();
}

// 選択範囲をオブジェクトとして保存する
function saveSelection(selection) {
	if (!selection || selection.isEmpty) return null;

	return {
		mode: selection.Mode,
		topX: selection.GetTopPointX(eePosLogical),
		topY: selection.GetTopPointY(eePosLogical),
		bottomX: selection.GetBottomPointX(eePosLogical),
		bottomY: selection.GetBottomPointY(eePosLogical)
	};
}

// 選択範囲をオブジェクトから復元する
function restoreSelection(selection, obj) {
	if (!selection || !obj) return;

	selection.Mode = obj.Mode;
	selection.SetActivePoint(eePosLogical, obj.topX, obj.topY, false);
	selection.SetActivePoint(eePosLogical, obj.bottomX, obj.bottomY, true);
}

// メインメニューを作成
function buildMainMenu() {
	var mainMenu = CreatePopupMenu();
	menuItemInfo = { };
	addReplaceFilesMenu(mainMenu);
	mainMenu.Add("", 0, eeMenuSeparator);
	addTargetSubMenu(mainMenu);
	mainMenu.Add("自動保存(&S)", 2000, (autoSaveAfterReplace ? eeMenuChecked : 0));
	mainMenu.Add("バックアップ(&B)", 2001, (backup ? eeMenuChecked : 0));
	return mainMenu;
}

// 置換リスト選択メニューを追加
function addReplaceFilesMenu(menu) {
	menu.Add("置換リストファイルを選択(&R)...", 1);

	// 置換リストが読み込まれていればメニューに追加
	if (replaceFileList && replaceFileList.length > 0) {
		menu.Add("", 0, eeMenuSeparator);
		addReplaceFileList(menu, replaceFileList, 2);
	}
}

// 置換リストを追加
// id は開始メニューアイテムID
function addReplaceFileList(menu, list, id) {
	for(var i in list) {
		var item = list[i];
		if (item.submenu) {
			// サブメニューを再帰的に追加
			var m = CreatePopupMenu();
			id = addReplaceFileList(m, item.item, id);
			menu.AddPopup(item.caption, m);
		}
		else if (item.caption == "-") {
			menu.Add("", 0, eeMenuSeparator);
		}
		else {
			// アイテム情報(ファイルパス)を覚えておく
			menuItemInfo["id" + id] = item.item;
			menu.Add(item.caption, id++);
		}
	}
	return id;
}

// 置換対象のサブメニューを追加
function addTargetSubMenu(menu) {
	var targetSubMenu = CreatePopupMenu();
	var targetChecked = false;
	var targetCaption = "選択されていません";

	// メニューアイテムを追加する
	//   caption = 項目のキャプション
	//   acc = アクセラレータ
	//   id = メニューアイテムID
	//   checked = チェックされているかどうか
	//   captionAfter = アクセラレータの後ろに表示するキャプション
	var addMenu = function(caption, acc, id, checked, captionAfter) {
		var after = checked && captionAfter ? captionAfter : "";
		var menuCaption = caption + acc + after;
		if (checked) {
			targetChecked = true;
			targetCaption = caption + after;
			targetSubMenu.Add(menuCaption, id, eeMenuChecked);
		} else {
			targetSubMenu.Add(menuCaption, id);
		}
	}
	// セパレータを追加する
	var addSeparator = function() {
		targetSubMenu.Add("", 0, eeMenuSeparator);
	}

	menuItemInfo["id1000"] = document;
	addMenu("このドキュメント", "(&A)", 1000,
	        typeof(target) == "object" && target == document);

	addSeparator();

	var docs = new Enumerator(editor.Documents);
	for(var i = 0; !docs.atEnd(); docs.moveNext(), i++) {
		var doc = docs.item();
		if (doc == document) continue;
		menuItemInfo["id" + (1001 + i)] = doc;
		addMenu(doc.Name, generateAcc(i), 1001 + i,
		        typeof(target) == "object" && target == doc);
	}

	addSeparator();

	addMenu("ファイルを選択", "(&F)...", 1500,
	        !targetChecked &&  targetIsFile, " : " + target);

	addMenu("フォルダを選択", "(&D)...", 1501,
	        !targetChecked && !targetIsFile, " : " + target);

	addSeparator();

	addMenu("サブフォルダも対象にする", "(&R)", 1502, searchInSubFolder);

	menu.AddPopup("置換の対象(&T) : " + targetCaption, targetSubMenu);
	return targetSubMenu;
}

// アクセラレータを作成する
function generateAcc(c) {
	c = c.toString();
	if (c.length != 1) return "";
	else return "(&" + c + ")";
}

// ファイルを開くダイアログ
function openFileDialog() {
	var doc = document;
	var num = editor.Documents.Count;
	editor.ExecuteCommandByID(4097);
	if (doc == document) { return ""; }

	var fileName = document.FullName;

	if (num < editor.Documents.Count) document.close();
	doc.Activate();
	return fileName;
}

// フォルダを開くダイアログ
function openFolderDialog() {
	var shapp = new ActiveXObject("Shell.Application");
	var folder = shapp.BrowseForFolder(0, "フォルダを選択してください", 0x50, "");
	if (folder) {
		return winxp ? folder.Self.Path : folder.Items.Item(0).Path;
	} else {
		return "";
	}
}

タグ:

+ タグ編集
  • タグ:

このサイトはreCAPTCHAによって保護されており、Googleの プライバシーポリシー利用規約 が適用されます。

添付ファイル
目安箱バナー