Java の ASCII Property ファイル向け WinMerge 展開プラグイン。
ASCIIコードは義務なんです。
国際文字対応してますか?
義務ですよ。🙃
果たしてますか?
(追記) 2024/10/31(木) WinMerge v2.16.44 がリリースされました。
WinMerge 2.16.44 Release Notes
(中略)
What Is New in 2.16.43 Beta
(中略)
Plugins
Create CompareEscapedJavaPropertiesFiles.sct (PR #2455)
ヽ(゚∀゚)ノ
CompareEscapedJavaPropertiesFiles.sct
として同梱され、
[ファイル] > [展開プラグイン] > [Java プロパティファイルをアンエスケープ]
を選択することで利用できる様になりました!
ひゃっほい
概要
まだまだPropertyファイルでASCIIを使っている現場を目の当たりにして。これからも辛酸を舐めそうで。特にDIFFるとき用にとWinMergeの展開プラグインを作った。
青果物
<scriptlet>
<implements type="Automation" id="dispatcher">
<property name="PluginEvent">
<get/>
</property>
<property name="PluginDescription">
<get/>
</property>
<property name="PluginFileFilters">
<get/>
</property>
<property name="PluginIsAutomatic">
<get/>
</property>
<method name="UnpackFile"/>
<method name="PackFile"/>
</implements>
<script language="JScript">
/**
* define.
* https://learn.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/opentextfile-method
*/
var IOMode = {
ForReading: 1,
ForWriting: 2,
ForAppending: 8
};
var Format = {
TristateUseDefault: -2, // system
TristateTrue: -1, // UNICODE
TristateFalse: -0 // ASCII
};
/** general. */
var fso = new ActiveXObject('Scripting.FileSystemObject');
var wsh = new ActiveXObject('WScript.Shell');
/**
* ReaddAllTextFile.
* @param filePath
* @param format
* @return text
*/
function readTextFile(filePath, format) {
var stream = null;
try {
stream = fso.OpenTextFile(filePath, IOMode.ForReading, false, format);
return stream.ReadAll();
} finally {
if(stream) {
stream.Close();
}
}
}
/**
* writeTextFile
* @param filePath
* @param text
* @param format
*/
function writeTextFile(filePath, text, format) {
var stream = null;
try {
stream = fso.OpenTextFile(filePath, IOMode.ForWriting, true, format);
stream.Write(text);
} finally {
if(stream) {
stream.Close();
}
}
}
/**
* get_PluginEvent
* @return description.
*/
function get_PluginEvent() {
return 'FILE_PACK_UNPACK';
}
/**
* get_PluginDescription
* @return description.
*/
function get_PluginDescription() {
return 'diff property file.';
}
/**
* get_PluginFileFilters
* @return file name patern filter.
*/
function get_PluginFileFilters() {
return '\.properties$;\.property$';
}
/**
* get_PluginIsAutomatic
* @return is automatic.
*/
function get_PluginIsAutomatic() {
return true;
}
/**
* UnpackFile
* @param fileSrc source file path.
* @param fileDst target file path for display.
* @param pbChanged
* @param pSubcode
* @return
*/
function UnpackFile(fileSrc, fileDst, pbChanged, pSubcode) {
var result = new ActiveXObject('Scripting.Dictionary');
var srcText = readTextFile(fileSrc, Format.TristateFalse);
var convertedText = srcText.replace(/\\u([0-9a-fA-F]{4})/g, function(_, p1) {
return String.fromCharCode(parseInt(p1, 16));
});
writeTextFile(fileDst, convertedText, Format.TristateTrue);
result.Add(0, true);
// pbChanged
result.Add(1, true);
// pSubcode
result.Add(2, 0);
return result.Items();
}
/**
* PackFile
* @param fileSrc edited file path file for replace.
* @param fileDst not use.
* @param pbChanged
* @param pSubcode
* @return
*/
function PackFile(fileSrc, fileDst, pbChanged, pSubcode) {
var result = new ActiveXObject('Scripting.Dictionary');
var srcText = readTextFile(fileSrc, Format.TristateTrue);
var convertedText = '';
for(var i = 0; i < srcText.length; i++) {
var c = srcText.charAt(i);
var cp = srcText.charCodeAt(i);
if(cp <= 0x007F) {
// ASCII
convertedText += c;
} else {
// Unicode Escape Sequence.
convertedText += '\\u' + ('0000' + cp.toString(16)).slice(-4);
}
}
writeTextFile(fileSrc, convertedText, Format.TristateFalse);
result.Add(0, true);
// pbChanged
result.Add(1, true);
// pSubcode
result.Add(2, 0);
return result.Items();
}
</script>
</scriptlet>
使いかた
環境
- WinMerge 2.16.42.1
※ 古いと動かない可能性あり。
インストール
# | 手順 | 内容 |
---|---|---|
1 | 上記スクリプトを保存する。 | (ファイル名)CompareJavaAsciiPropertyFile.sct
|
2 | WinMergeのプラグイン フォルダに配置する。 | (一般的なインストール先の場合)C:\Program Files\WinMerge\MergePlugins
|
使い方
-
展開プラグインを指定して比較する。
-
手動で展開プラグインを指定する。
※ 自動展開は有効にしないのがおすすめ。 (ASCII化されているPropertyファイルの方がいまや少ない (?) ので。)
効果
-
native2ascii
で reverse しなくても、可読性の比較ができる。
- そのまま編集保存が可能。(
native2ascii
でASCII化する必要なし。 ) - 開発効率の向上
※[要出典] 今更どのプロジェクトで? (苦笑)
WinMergeのプラグイン説明
説明資料などがなく、いくつか推察も含んでいる旨ご容赦。
実装
今回は、展開 ⇔ 保存 が相互に行える、 展開プラグイン として以下のメソッドを実装。
プロパティ
property (method) |
return | discription |
---|---|---|
PluginEvent (get_PluginEvent()) |
string |
展開プラグインの定数。FILE_PACK_UNPACK
|
PluginDescription (get_PluginDescription()) |
string |
プラグインの説明。 |
PluginFileFilters (get_PluginFileFilters()) |
string |
プラグインを自動適用する場合のファイル名フィルター。 |
PluginIsAutomatic (get_PluginIsAutomatic()) |
boolean |
自動展開可能可否。 |
メソッド
UnpackFile
arg1 | string |
fileSrc | WinMergeに指定されたファイル パス。 例): Z:\MergePlugin - Property Files\application_ja.properties
|
arg2 | string |
fileDst | 展開後、比較に用いられるファイルのパス。 コールバックされたときはまだファイルは存在しない。変更内容で生成する。 例): C:\Users\xxxx\AppData\Local\Temp\WinMerge_TEMP_20292\_WM70B3.tmp.properties
|
arg3 | boolean |
pbChanged | 変更有無のフラグ。(本来はポインタ) |
arg4 | boolean |
pSubcode | 用途不明。(本来はポインタ) |
return | Scripting.Dictionary.Items() |
実行の成否を含んだ複数の戻り値。pbChanged やpSubcode が参照渡し出来ないための辞書返しと思われる。 |
/**
* UnpackFile
* @param fileSrc source file path.
* @param fileDst target file path for display.
* @param pbChanged
* @param pSubcode
* @return
*/
function UnpackFile(fileSrc, fileDst, pbChanged, pSubcode) {
var result = new ActiveXObject('Scripting.Dictionary');
// ASCIIで読み取り。
var srcText = readTextFile(fileSrc, Format.TristateFalse);
// Unicodeエスケープ シーケンスを正規表現で見つけ、文字に一括置換する。。
var convertedText = srcText.replace(/\\u([0-9a-fA-F]{4})/g, function(_, p1) {
return String.fromCharCode(parseInt(p1, 16));
});
// Unicode (USC2) で書き出し。
writeTextFile(fileDst, convertedText, Format.TristateTrue);
// 戻り値
result.Add(0, true);
result.Add(1, true); // pbChanged?
result.Add(2, 0); // pSubcode?
return result.Items();
}
readTextFile()
writeTextFile()
は言うまでもない共通処理のため割愛。
PackFile
arg1 | string |
fileSrc | WinMerge上で編集された内容のファイル。 ※変更がある場合は、このファイルに対して変更をする (上書きする)。 例): C:\Users\xxxx\AppData\Local\Temp\WinMerge_TEMP_20292\MRG5F99.tmp
|
arg2 | string |
fileDst | 用途不明。 コールバックされたときはまだファイルは存在しない。 例): C:\Users\xxxx\AppData\Local\Temp\WinMerge_TEMP_20292\_WM5F9A.tmp
|
arg3 | boolean |
pbChanged | 用途不明。(本来はポインタ) |
arg4 | boolean |
pSubcode | 用途不明。(本来はポインタ) |
return | Scripting.Dictionary.Items() |
実行の成否を含んだ複数の戻り値。pbChanged やpSubcode が参照渡し出来ないための辞書返しと思われる。 |
え? fileSrc
から読み取って fileDst
を作成するんじゃないの!!!😲
え? fileSrc
を上書き・・・🤔???
/**
* PackFile
* @param fileSrc edited file path file for replace.
* @param fileDst not use.
* @param pbChanged
* @param pSubcode
* @return
*/
function PackFile(fileSrc, fileDst, pbChanged, pSubcode) {
var result = new ActiveXObject('Scripting.Dictionary');
// Unicode (USC2) で読み取り (UnpackFile時と同じコード)。
var srcText = readTextFile(fileSrc, Format.TristateTrue);
var convertedText = '';
// ASCII文字以外の文字をUnicodeエスケープ シーケンスに置き換えた文字列を生成する。
for(var i = 0; i < srcText.length; i++) {
var c = srcText.charAt(i);
var cp = srcText.charCodeAt(i);
if(cp <= 0x007F) {
// ASCII
convertedText += c;
} else {
// Unicode Escape Sequence.
convertedText += '\\u' + ('0000' + cp.toString(16)).slice(-4);
}
}
// ASCIIで上書き保存。
writeTextFile(fileSrc, convertedText, Format.TristateFalse);
// 戻り値
result.Add(0, true);
result.Add(1, true); // pbChanged?
result.Add(2, 0); // pSubcode?
return result.Items();
}
※ readTextFile()
writeTextFile()
は言うまでもない共通処理のため割愛。
所感
実は native2ascii
な現場で従事して10年余りにわたりフラストレーションをため続けていた。リポジトリと衝突したときに確認がしづらかったり。言語ファイル同士で単語状況を確認したかったりなど。もっとも、あまり application.properties を編集することないのだけど。
ただ、今後まだまだ付き合いが長くなることに合わせて。せっかくなのでWinMergeのプラグインの作成にチャレンジをしてみた。
正直情報が無く、デバッグもしづらくて大変だった。。。
_ (┐「ε:)_
VBScriptのオワコンでプラグイン仕様が変わったのか、JScriptの情報もなかったり動かなかったりで。。。
JScriptでできるのか?
ネイティブ文字コードのJScriptで国際文字対応できるのか?
やっぱCでDLL作るか?
でも文字コードが厄介だなぁ。。
ならC++CLIか?
とか色々悩んだんだけど。今回は、WSHで読み書きするUSC2がそのままWinMergeでも扱えたことが結構助かった。
application.properties向け比較ツールを作る ことも頭をよぎりつつ、DIFFツールの再開はムリゲー。と言うか20年以上付き合っていて、実績も多分にあるWinMergeに近づくなんて恐れ多いし。。。など悩んでいたので。今回プラグインを作成出来て大変良かった。
ぶっちゃけ、WinMergeの展開プラグインでPackメソッドを実装しているものがなく、情報も無くて大変だったけど。これが本家に取り込まれないかなぁ、とか妄想なんかもしてみたり。(恐れ多い!)
謝辞🙇
- WinMerge
https://winmerge.org/ - プラグイン - WinMerge 2.16 ヘルプ
https://manual.winmerge.org/jp/Plugins.html - WinMergeのプラグインについて(開発者向け) #Windows - Qiita
https://qiita.com/kenichiuda/items/1d0f4e0a543854f3c27c - WinMergeでJSONデータを整形して比較する #beatsaber - Qiita
https://qiita.com/rynan4818/items/1c904ef60afcecc9bbd5 - winmerge/Plugins/dlls/CompareMSExcelFiles.sct at master · WinMerge/winmerge
https://github.com/WinMerge/winmerge/blob/master/Plugins/dlls/CompareMSExcelFiles.sct - javaのプロパティファイルを比較するWinMergeプラグイン | 日々の反省1
https://highmt.wordpress.com/2011/03/17/javaのプロパティファイルを比較するwinmergeプラグイン/ - String.prototype.replace() - JavaScript | MDN
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/replace - native2ascii
https://docs.oracle.com/javase/jp/8/docs/technotes/tools/unix/native2ascii.html
Discussion