Skip to content

Instantly share code, notes, and snippets.

@jca02266
Created November 25, 2017 10:15
Show Gist options
  • Save jca02266/221b412ca59ef3b21ebf8dc7f950040d to your computer and use it in GitHub Desktop.
Save jca02266/221b412ca59ef3b21ebf8dc7f950040d to your computer and use it in GitHub Desktop.
//
// sakura用桁揃えマクロ
//
// drived from http://zenu.xrea.jp (http://zenu.xrea.jp/data/quickint.js.txt)
//
// 使い方:
// 1. このファイルを %AppData%\sakura に配置する
// 2. 桁揃えしたい範囲を選択する
// 3. ツール → 「名前を指定してマクロを実行」でこのファイルを選択する
//
// ※ あらかじめ 「設定」→「共通設定」→「マクロ」に登録済みマクロとして登録しても良い
//
// alert() のvbsによる実装
var vbs = {
_control: new ActiveXObject("ScriptControl"),
_lang : "VBScript",
_escape: function(v) {
return (("" + v).replace(/\x22/g, '""').replace(/[\r\n]+/g, '" & vbCrLf & "'));
},
prompt : function (msg, title, def) {
return (this.eval('InputBox(' +
'"' + this._escape(msg ) + '", ' +
'"' + this._escape(title || '') + '", ' +
'"' + this._escape(def || '') + '")'));
},
alert : function (msg) {
this.exec('MsgBox("' + this._escape(msg) + '")');
},
exec : function (src) {
this._control.Language = this._lang;
this._control.AddCode(src);
},
eval : function (src) {
this._control.Language = this._lang;
this._control.AddCode("Function Hoge() : Hoge = " + src + " : End Function");
return (this._control.Run("Hoge"));
}
};
function dump(v) {
var s = '';
for (var c in v) {
s += c + ' = ' + v[c] + '\n';
}
vbs.alert(s);
}
// like the Polyfill
Array.prototype.forEach = function(fn, that) {
for (var i = 0; i < this.length; i++) {
fn.call(that, this[i], i, this);
}
};
Array.prototype.map = function(fn, that) {
var ary = [];
for (var i = 0; i < this.length; i++) {
ary.push(fn.call(that, this[i], i, this));
}
return ary;
};
Array.prototype.minIndex = function(fn) {
if (this.length < 1) {
return;
}
var index = 0;
var min = fn(this[index]);
for (var i = 1; i < this.length; i++) {
var tmp = fn(this[i]);
if (tmp < min) {
min = tmp;
index = i;
}
}
return index;
};
Array.prototype.maxIndex = function(fn) {
if (this.length < 1) {
return;
}
var index = 0;
var max = fn(this[index]);
for (var i = 1; i < this.length; i++) {
var tmp = fn(this[i]);
if (tmp > max) {
max = tmp;
index = i;
}
}
return index;
};
Array.prototype.min = function(fn) {
var i = this.minIndex(fn);
return this[i];
}
Array.prototype.max = function(fn) {
var i = this.maxIndex(fn);
return this[i];
}
String.prototype.repeat = function (n) {
var s = '';
for (var i = 0; i < n; i++) {
s += this.toString();
}
return s;
};
String.prototype.splice = function (start, delCount, newSubStr) {
return this.slice(0, start) + newSubStr + this.slice(start + Math.abs(delCount));
}
String.prototype.eachLine = function (fn) {
var start = 0;
var arr = [];
while (true) {
var found = this.indexOf("\n", start);
if (found === -1) {
var s = this.slice(start);
if (s.length > 0) {
arr.push(fn(s));
}
return arr;
}
arr.push(fn(this.slice(start, found + 1)));
start = found + 1;
}
}
// Specific functions for this macro
// 文字列sの各文字のうち、最も左で見つかったインデックスを返す
String.prototype.indexChar = function (s, index) {
var lastindex = -1;
for (var i = 0; i < s.length; i++) {
var v = this.indexOf(s.charAt(i), index);
if (v >= 0 && (lastindex < 0 || v < lastindex)) {
lastindex = v;
}
}
return lastindex;
};
function bytesize(s, index) {
var codepoint = s.charCodeAt(index || 0);
// ASCII
if (codepoint < 0x100) {
return 1;
}
// Halfwidth CJK punctuation, Halfwidth Katakana variants
if (0xFF61 <= codepoint && codepoint <= 0xFF9F) {
return 1;
}
return 2;
}
function bytewidth(s, len) {
var ret = 0;
for (var i = 0; i < len; i++) {
ret += bytesize(s, i);
}
return ret;
}
function LineObject(line, lastindex) {
this.str = line;
this.lastindex = lastindex || 0;
}
function main(args) {
if (args.length == 0) {
throw new Error("整形したい範囲を選択してください");
}
var cstr = vbs.prompt("記号を入力してください。\nカンマと閉じ括弧は右にパディングされます。", "桁揃え記号", ",=");
if (!cstr || cstr.length == 0) {
return args;
}
var lines = args.eachLine(function (line) { return new LineObject(line); });
while (true) {
// 1. 区切り文字に関する情報(インデックス, サイズ(column), 文字(char))を抽出
var xs = [];
for (var i = 0; i < lines.length; i++) {
if (lines[i].lastindex < 0) {
continue;
}
lines[i].lastindex = lines[i].str.indexChar(cstr, lines[i].lastindex);
if (lines[i].lastindex < 0) {
continue;
}
xs.push({
idx: i,
column: bytewidth(lines[i].str, lines[i].lastindex),
char: lines[i].str.charAt(lines[i].lastindex)
});
}
if (xs.length <= 1) {
// 区切り文字を含む行がない。または、1行で桁揃えの必要がない
break;
}
// 2. 最左にある区切り文字を取得
var mlchar = xs.min(function(v) { return v.column; }).char; // 最左文字(most-left-char)
// 3. 2で取得した区切り文字と同じ文字で最右にあるものを取得
var mrcolumn = xs.max(function(v) {
if (mlchar === v.char) {
return v.column;
}
return -1;
}).column; // 最右カラム(most-right-column)
// 4. 区切り文字の位置を3の最右にそろえる
var lenback = 0;
if (mlchar.indexChar(",)]}") !== -1) {
// , ) ] } の後を揃える
lenback = 1;
}
xs.forEach(function (v) {
if (v.char == mlchar && v.column <= mrcolumn) {
line = lines[v.idx];
var index = line.lastindex + lenback;
var spaceCount = mrcolumn - v.column;
var delCount = 0;
if (lenback) {
while (line.str.charAt(index+delCount) === ' ') {
delCount++;
}
}
var s = line.str.splice(index, delCount, " ".repeat(spaceCount));
line.lastindex += spaceCount + 1;
lines[v.idx] = new LineObject(s, line.lastindex);
}
});
}
return lines.map(function(v) { return v.str; }).join("");
}
Editor.InsText(main(Editor.GetSelectedString(0)));
//
// sakura用マクロ: where句用 TSV→CSV変換
//
// TSV形式の文字列(SQL Developerから取得したレコードなど)を
// SQLのwhere句に利用できるCSV (シングルクォート、括弧付き)に変換する
//
// 例:
//
// a b c
// d e f
// ↓
// ('a','b','c')
// ,('d','e','f')
//
// 使い方:
// 1. このファイルを %AppData%\sakura に配置する
// 2. lib/shim.js を %AppData%\sakura\lib に配置する
// 3. 変換したい範囲を選択する
// 4. ツール → 「名前を指定してマクロを実行」でこのファイルを選択する
//
// ※ あらかじめ 「設定」→「共通設定」→「マクロ」に登録済みマクロとして登録しても良い
//
require("shim");
function main(args) {
if (args.length == 0) {
throw new Error("変換対象範囲を選択してください");
}
var lines = args.eachLine(function (line) { return line; });
for (var i = 0; i < lines.length; i++) {
var line = lines[i];
line = "('" + line.replace(/\t/g, "','").replace(/(\r?\n)/, "')$1");
if (i == 0) {
line = " " + line;
}
else {
line = " ," + line;
}
lines[i] = line;
}
return lines.join("");
}
Editor.InsText(main(Editor.GetSelectedString(0)));
// END OF SCRIPT ////////////
function alert(message) {
var WSHShell = new ActiveXObject("WScript.Shell");
WSHShell.Popup('' + message, 0, "title", 1);
}
// eval で、CommonJS の require を模倣する
// require されたスクリプトは汚染されるので例えばファイル出力等はできない
function require(filepath) {
filepath = filepath.replace(/\.js$/, '') + ".js";
var source = (function(path) {
var fs = new ActiveXObject("Scripting.FileSystemObject");
var expandPath = function (path) {
if (path.match(/^(\\\\|[a-zA-z]:\\|\\)/)) {
return path; // fullpath
}
var WSHShell = new ActiveXObject("WScript.Shell");
var env = WSHShell.Environment("PROCESS");
var fullpath;
var dirs = [env("APPDATA") + "\\sakura\\lib", ".\\lib"];
for (var i = 0; i < dirs.length; i++) {
fullpath = dirs[i] + "\\" + path;
if (fs.FileExists(fullpath)) {
return fullpath;
}
}
return;
}
var fullpath = expandPath(path);
if (!fullpath) {
throw new Error("require(): ファイル(" + path + ")が見つかりません");
}
var file = fs.OpenTextFile(fullpath);
var source = file.ReadAll();
file.Close();
return source;
})(filepath);
var module = (function() {
var module = {exports: {}};
eval(source);
return module;
})();
return module.exports;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment