Skip to content

Instantly share code, notes, and snippets.

@Infocatcher
Last active August 29, 2015 13:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Infocatcher/9952951 to your computer and use it in GitHub Desktop.
Save Infocatcher/9952951 to your computer and use it in GitHub Desktop.
Test version of winMergeTabs.js, for http://akelpad.sf.net/forum/viewtopic.php?p=24441#24441
// http://akelpad.sourceforge.net/forum/viewtopic.php?p=21354#21354
// http://infocatcher.ucoz.net/js/akelpad_scripts/winMergeTabs.js
// https://github.com/Infocatcher/AkelPad_scripts/blob/master/winMergeTabs.js
// (c) Infocatcher 2013
// version 0.1.1.1 - 2013-08-07
// Compare contents of current and next selected tab using WinMerge (http://winmerge.org/)
// or any other compare tool
// Arguments:
// -path="%ProgramFiles%\WinMerge\WinMerge.exe" - path to WinMerge executable
// (or many paths: "path1|path2|path3")
// -cmd="<exe> /S=C <f1> <f2>" - set custom command line for any other compare tool
// (an example for Total Commander)
// -save=true - true - save (already saved, but modified) file before compare
// false - use temporary files for modified files
// -temp="%AkelScripts%\temp" - path to temporary directory
// -useTabsOrder=true - always compare left tab with right tab
// Usage:
// Call("Scripts::Main", 1, "winMergeTabs.js")
// Call("Scripts::Main", 1, "winMergeTabs.js", '-path="%COMMANDER_PATH%\TOTALCMD.EXE" -cmd="<exe> /S=C <f1> <f2>"')
function _localize(s) {
var strings = {
"No tabs!": {
ru: "Отсутствуют вкладки!"
},
"MDI or PMDI window mode required!": {
ru: "Требуется оконный режим MDI или PMDI!"
},
"WinMerge not found!": {
ru: "Не удалось найти WinMerge!"
},
"Select tab!": {
ru: "Выберите вкладку!"
},
"Not found file from first tab:\n": {
ru: "Не найден файл из первой вкладки:\n"
},
"Not found file from second tab:\n": {
ru: "Не найден файл из второй вкладки:\n"
}
};
var lng;
switch(AkelPad.GetLangId(1 /*LANGID_PRIMARY*/)) {
case 0x19: lng = "ru"; break;
default: lng = "en";
}
_localize = function(s) {
return strings[s] && strings[s][lng] || s;
};
return _localize(s);
}
var paths = AkelPad.GetArgValue("path", "");
var cmdLineTemplate = AkelPad.GetArgValue("cmd", "<exe> <f1> <f2>");
var save = AkelPad.GetArgValue("save", false);
var tempDir = AkelPad.GetArgValue("temp", "%temp%");
var useTabsOrder = AkelPad.GetArgValue("useTabsOrder", false);
var winMergePaths = paths
? paths.split("|")
: [
"<HKCU\\Software\\Thingamahoochie\\WinMerge\\Executable>",
"<HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\WinMergeU.exe\\>",
"<HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\WinMerge.exe\\>",
"%ProgramFiles%\\WinMerge\\WinMergeU.exe",
"%ProgramFiles (x86)%\\WinMerge\\WinMergeU.exe",
"%AkelDir%\\..\\WinMergePortable\\WinMergePortable.exe",
"%COMMANDER_PATH%\\..\\WinMergePortable\\WinMergePortable.exe"
];
var hMainWnd = AkelPad.GetMainWnd();
var oSys = AkelPad.SystemFunction();
var fso = new ActiveXObject("Scripting.FileSystemObject");
var wsh = new ActiveXObject("WScript.Shell");
if(
hMainWnd
&& AkelPad.IsMDI() // WMD_MDI or WMD_PMDI
) {
var lpFrame = AkelPad.SendMessage(hMainWnd, 1288 /*AKD_FRAMEFIND*/, 1 /*FWF_CURRENT*/, 0);
var lpFrame2;
if(lpFrame) {
var statusbar = new Statusbar();
statusbar.save();
var statusMsg = _localize("Select tab!");
statusbar.set(statusMsg);
if(AkelPad.Include("timer.js")) {
var showDelay = 600;
var hideDelay = 150;
// show -> [showDelay] -> hide -> [hideDelay] -> show -> [showDelay] -> hide
var timerHide = setTimeout(function() {
statusbar.set("");
clearTimeout(timerHide);
timerHide = setInterval(function() {
statusbar.set("");
}, showDelay + hideDelay, timerHide);
}, showDelay);
var timerShow = setInterval(function() {
statusbar.set(statusMsg);
}, showDelay + hideDelay);
var stopTimers = function() {
clearInterval(timerHide);
clearInterval(timerShow);
};
}
}
if(
lpFrame
&& AkelPad.WindowSubClass(
1 /*WSC_MAINPROC*/,
mainCallback,
0x416 /*AKDN_FRAME_ACTIVATE*/,
0x418 /*AKDN_FRAME_DESTROY*/
)
) {
AkelPad.ScriptNoMutex(5 /*ULT_UNLOCKSCRIPTSQUEUE|ULT_LOCKMULTICOPY*/); // Allow other scripts running
AkelPad.WindowGetMessage(); // Message loop
AkelPad.WindowUnsubClass(1 /*WSC_MAINPROC*/);
AkelPad.ScriptNoMutex(8 /*ULT_UNLOCKMULTICOPY*/);
stopTimers && stopTimers();
statusbar.restore();
if(lpFrame2)
compareTabs(lpFrame, lpFrame2);
}
else {
stopTimers && stopTimers();
statusbar && statusbar.restore();
AkelPad.MessageBox(hMainWnd, _localize("No tabs!"), WScript.ScriptName, 48 /*MB_ICONEXCLAMATION*/);
}
}
else {
AkelPad.MessageBox(hMainWnd, _localize("MDI or PMDI window mode required!"), WScript.ScriptName, 48 /*MB_ICONEXCLAMATION*/);
}
function mainCallback(hWnd, uMsg, wParam, lParam) {
if(uMsg == 0x416 /*AKDN_FRAME_ACTIVATE*/) {
if(lParam != lpFrame) {
lpFrame2 = lParam;
oSys.Call("user32::PostQuitMessage", 0); // Exit message loop
}
}
else if(uMsg == 0x418 /*AKDN_FRAME_DESTROY*/) {
if(lParam == lpFrame)
oSys.Call("user32::PostQuitMessage", 0); // Exit message loop
}
}
function compareTabs(lpFrame, lpFrame2) {
var winMerge = getWinMerge();
if(!winMerge) {
AkelPad.MessageBox(
hMainWnd,
_localize("WinMerge not found!") + "\n\n" + getWinMergePaths(),
WScript.ScriptName,
48 /*MB_ICONEXCLAMATION*/
);
return;
}
setRedraw(hMainWnd, false);
var file = getFile(lpFrame);
var file2 = getFile(lpFrame2);
//if(AkelPad.SendMessage(hMainWnd, 1288 /*AKD_FRAMEFIND*/, 1 /*FWF_CURRENT*/, 0) != lpFrame2)
// AkelPad.SendMessage(hMainWnd, 1285 /*AKD_FRAMEACTIVATE*/, 0, lpFrame2);
setRedraw(hMainWnd, true);
// Force redraw current edit window
oSys.Call("user32::InvalidateRect", AkelPad.GetEditWnd(), 0, true);
var noFile = !fso.FileExists(file);
var noFile2 = !fso.FileExists(file2);
if(noFile || noFile2) {
var errs = [];
if(noFile)
errs[errs.length] = _localize("Not found file from first tab:\n") + file;
if(noFile2)
errs[errs.length] = _localize("Not found file from second tab:\n") + file2;
AkelPad.MessageBox(
hMainWnd,
errs.join("\n\n"),
WScript.ScriptName,
48 /*MB_ICONEXCLAMATION*/
);
if(!noFile && file.isTemp)
fso.DeleteFile(file);
if(!noFile2 && file2.isTemp)
fso.DeleteFile(file2);
return;
}
if(useTabsOrder) {
var pos = AkelPad.SendMessage(hMainWnd, 1294 /*AKD_FRAMEINDEX*/, 0, lpFrame);
var pos2 = AkelPad.SendMessage(hMainWnd, 1294 /*AKD_FRAMEINDEX*/, 0, lpFrame2);
if(pos2 < pos) {
var tmp = file;
file = file2;
file2 = tmp;
}
}
var cmdLine = cmdLineTemplate
.replace("<exe>", '"' + winMerge + '"')
.replace("<f1>", '"' + file + '"')
.replace("<f2>", '"' + file2 + '"');
var wm = wsh.Exec(cmdLine);
if(file.isTemp || file2.isTemp) {
// If WinMerge are already opened, new process will be immediately closed,
// so don't delete files too early
WScript.Sleep(4000);
for(;;) {
if(wm.Status != 0) {
if(file.isTemp)
fso.DeleteFile(file);
if(file2.isTemp)
fso.DeleteFile(file2);
break;
}
WScript.Sleep(1500);
}
}
}
function getFile(lpFrame) {
AkelPad.SendMessage(hMainWnd, 1285 /*AKD_FRAMEACTIVATE*/, 0, lpFrame);
var hWndEdit = AkelPad.GetEditWnd();
var origFile = AkelPad.GetEditFile(hWndEdit);
var file = origFile;
if(!origFile || AkelPad.SendMessage(hWndEdit, 3086 /*AEM_GETMODIFY*/, 0, 0)) {
if(origFile && save)
AkelPad.Command(4105); // IDM_FILE_SAVE
else {
var tempFile = file = getTempFile(hWndEdit, origFile);
var codePage = -1;
var hasBOM = -1;
if(!origFile) {
// Will use UTF-8 with BOM to correctly save all (most?) new documents
codePage = 65001;
hasBOM = 1;
}
AkelPad.SaveFile(AkelPad.GetEditWnd(), tempFile, codePage, hasBOM, 0 /* W/o SD_UPDATE */);
}
}
return file;
}
function getWinMerge() {
for(var i = 0, l = winMergePaths.length; i < l; ++i) {
var path = expandVariables(winMergePaths[i]);
if(fso.FileExists(path))
return path;
}
return "";
}
function getWinMergePaths() {
var out = [];
for(var i = 0, l = winMergePaths.length; i < l; ++i) {
var rawPath = winMergePaths[i];
var path = expandVariables(rawPath);
out[out.length] = path == rawPath
? path
: rawPath + " => " + path
}
return out.join("\n");
}
function getTempFile(hWndEdit, file) {
var fileName, fileExt;
var tmp = file && /[^\/\\]+$/.test(file) && RegExp.lastMatch;
if(tmp) {
fileExt = /\.[^.]+$/.test(tmp) && RegExp.lastMatch || "";
fileName = tmp.slice(0, -fileExt.length);
}
else {
fileExt = getCurrentExtension();
fileName = "akelpad-temp";
}
var tmpDir = expandVariables(tempDir);
if(!fso.FolderExists(tmpDir))
fso.CreateFolder(tmpDir);
var i = -1;
do tmp = tmpDir + "\\" + fileName + (++i ? "-" + i : "") + fileExt;
while(fso.FileExists(tmp));
var out = new String(tmp);
out.isTemp = true;
return out;
}
function getCurrentExtension() {
var alias = getCoderAlias();
if(/\.[^.]+$/.test(alias))
return RegExp.lastMatch;
return ".txt";
}
function getCoderAlias() {
// http://akelpad.sourceforge.net/forum/viewtopic.php?p=19363#19363
var hWndEdit = AkelPad.GetEditWnd();
var hDocEdit = AkelPad.GetEditDoc();
var pAlias = "";
if(hWndEdit && hDocEdit) {
var lpAlias = AkelPad.MemAlloc(256 * 2 /*sizeof(wchar_t)*/);
if(lpAlias) {
AkelPad.CallW("Coder::Settings", 18 /*DLLA_CODER_GETALIAS*/, hWndEdit, hDocEdit, lpAlias, 0);
pAlias = AkelPad.MemRead(lpAlias, 1 /*DT_UNICODE*/);
AkelPad.MemFree(lpAlias);
}
}
return pAlias;
}
function expandVariables(s) {
return expandEnvironmentVariables(expandRegistryVariables(s));
}
function expandEnvironmentVariables(s) {
if(s.substr(0, 9) == "%AkelDir%")
s = AkelPad.GetAkelDir() + s.substr(9);
if(s.substr(0, 13) == "%AkelScripts%")
s = AkelPad.GetAkelDir(5 /*ADTYPE_SCRIPTS*/) + s.substr(13);
return wsh.ExpandEnvironmentStrings(s);
}
function expandRegistryVariables(s) { // <HKCU\Software\Foo\installPath>\foo.exe
return s.replace(/<(.+?)>/g, function(s, path) {
var val = getRegistryValue(path);
if(val)
return val;
return s;
});
}
function getRegistryValue(path) {
try {
return wsh.RegRead(path);
}
catch(e) {
}
return "";
}
function setRedraw(hWnd, bRedraw) {
AkelPad.SendMessage(hWnd, 11 /*WM_SETREDRAW*/, bRedraw, 0);
bRedraw && oSys.Call("user32::InvalidateRect", hWnd, 0, true);
}
function Statusbar() {
this.get = this.set = this.save = this.restore = function() {};
// Based on Instructor's code: http://akelpad.sourceforge.net/forum/viewtopic.php?p=13656#13656
var hWndStatus = oSys.Call("user32::GetDlgItem", hMainWnd, 10002 /*ID_STATUS*/);
if(!hWndStatus || !oSys.Call("user32::IsWindowVisible", hWndStatus))
return;
var nParts = AkelPad.SendMessage(hWndStatus, 1030 /*SB_GETPARTS*/, 0, 0);
if(nParts <= 5)
return;
var _origStatus, _customStatus;
var _this = this;
function buffer(callback) {
var lpTextBuffer = AkelPad.MemAlloc(1024 * _TSIZE);
if(lpTextBuffer) {
var ret = callback.call(_this, lpTextBuffer);
AkelPad.MemFree(lpTextBuffer);
return ret;
}
return undefined;
}
this.get = function() {
return buffer(function(lpTextBuffer) {
AkelPad.SendMessage(hWndStatus, _TSTR ? 1037 /*SB_GETTEXTW*/ : 1026 /*SB_GETTEXTA*/, nParts - 1, lpTextBuffer);
return AkelPad.MemRead(lpTextBuffer, _TSTR);
});
};
this.set = function(pStatusText) {
buffer(function(lpTextBuffer) {
_customStatus = pStatusText;
AkelPad.MemCopy(lpTextBuffer, pStatusText, _TSTR);
AkelPad.SendMessage(hWndStatus, _TSTR ? 1035 /*SB_SETTEXTW*/ : 1025 /*SB_SETTEXTA*/, nParts - 1, lpTextBuffer);
});
};
this.save = function() {
_origStatus = this.get();
};
this.restore = function() {
if(_origStatus != undefined && this.get() == _customStatus)
this.set(_origStatus);
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment