sakai-memoru
12/1/2019 - 10:22 PM

Sakura Macro Library::app_commentInOut コードのコメント・アウトとコメント・イン

サクラエディタ上で、選択範囲(行単位で選択)を、行単位のコメント・アウト、コメント・インする。 (車輪の再発明な感じでもありますが・・・)

選択範囲中の一番小さいインデント行を基準に、コメントアウト、コメントインをする仕様です。

// app_commentInOut.jse  
// + sakura macro folder  
//    + app_commentInOut.jse  
//    + lib  
//      + StringUtil.jse  
//    + app_commentInOut  
//      + config  
//        + setting.js  
// 
(function(){

// const
var CONS_COMMON_LIBPATH = 'G:\\Users\\sakai\\AppData\\Roaming\\sakura';
var CONS_COMMON_LIBS = [
  // "./lib/es5-shim.js",
  // "./lib/json2.js",
  // "./lib/DateUtil.jse",
  "./lib/StringUtil.jse",
  //"./lib/Clipboard3.jse",
  //"./lib/ClipboardGetter.jse",
  //"./lib/Template.jse",
  //"./lib/Dialog.jse",
  "./app_commentInOut/config/setting.js",
]

var CONS_LOCAL_LIBPATH = '';
var CONS_LOCAL_LIBS = [
  //"G:\\Users\\sakai\\AppData\\Roaming\\sakura\\sandbox\\apps\\config\\setting.js"
]

// commonalized for js   /////////////////////////////////////////////
// load external libraries
var check_env = function(){
  // set env_name for targetting wsh, sakura, node
  var env_name = '';
  if (typeof(WScript) !== "undefined") env_name = 'wsh';
  if (typeof(Editor) !== "undefined") env_name = 'sakura';
  if (typeof(alert) !== "undefined") {env_name = 'browser';}
  else if (typeof(console) !== "undefined") env_name = 'node';
  return env_name;
}
var flag = check_env();
var CONFIG = {};

if(flag == "wsh"||flag == "sakura"){
  var objFS = new ActiveXObject("Scripting.FileSystemObject");
  var lib_path = CONS_COMMON_LIBPATH ? CONS_COMMON_LIBPATH: './';
  var llib_path = CONS_LOCAL_LIBPATH ? CONS_LOCAL_LIBPATH: '';
  // require common module
  with({
    libs : CONS_COMMON_LIBS, 
    llibs : CONS_LOCAL_LIBS,
    get_moduleCode : function(path){
      return objFS.OpenTextFile(path,1).ReadAll();
    }
  }) {
    var len = libs.length;
    for (var i = 0; i < len; i++){
      try {
        var module_path = objFS.BuildPath(lib_path,libs[i]);
        eval(get_moduleCode(module_path));
      } catch (e) {
        //console.log( e.description || e.message || "error" );
        null;
      }
    }
    var llen = llibs.length;
    for (var i = 0; i < llen; i++){
      try {
        var module_path = objFS.BuildPath(llib_path,llibs[i]);
        //Editor.TraceOut(module_path);
        eval(get_moduleCode(module_path));
      } catch (e) {
        //console.log( e.description || e.message || "error" );
        null;
      }
    }
  };
  objFS = null;
}

var debug_mode = CONFIG.DEBUG_MODE ;

// pretend console.log 
var console = console || {};
if(console){
  if(debug_mode){
    var typeOf = function(obj) {
      return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
    }
    var stringify_object = function(obj){
      if(typeOf(obj) !== 'object') return obj;
      var ary = [];
      for(var k in obj){
        if(obj.hasOwnProperty(k)){
          if(typeOf(obj) === 'boolean'){
            ary.push('"' + k + '"' + " : " +  stringify_object(obj[k]) + ' ');
          }else if(typeOf(obj) === 'number'){
            ary.push('"' + k + '"' + " : " +  stringify_object(obj[k]) + ' ');
          }else if(typeOf(obj) === 'array'){
            ary.push('"' + k + '"' + " : " +  stringify_object(obj[k]) + ' ');
          }else if(typeOf(obj) !== 'object'){
            ary.push('"' + k + '"' + " : " + '"' + stringify_object(obj[k]) + '" ');
          }else{
            ary.push('"' + k + '"' + " : " + stringify_object(obj[k]) + ' ');
          }
        }
      }
      var temp = ary.toString();
      temp = temp.substr(0, temp.length -1);
      return "{ " + temp + " }"
    }
    if(flag == "sakura"){
      console.log=function(str){
        var log_str = "[DEBUG] $d$t ($f) > " + str;
        Editor.TraceOut(log_str,1)
      }
      console.info=function(str){
        var log_str = "[INFO] $d$t ($f) > " + str;
        Editor.TraceOut(log_str,1)
      }
      console.dir = function(obj){
        var str = "[DUMP] $d$t ($f) > " + stringify_object(obj);
        Editor.TraceOut(str,1);
      }
    };
    if(flag == "wsh"){
      console.info = function(str){WScript.Echo('[INFO] ' + str)};
      console.log = function(str){WScript.Echo('[DEBUG] ' + str)};
      console.dir = function(obj){
        var str = stringify_object(obj);
        WScript.Echo('[DUMP] ' + str);
      }
    }
  }else{
    if(flag == "wsh")  console.info = function(str){WScript.Echo(str)};
    if(flag == "sakura")  console.info =function(str){Editor.InfoMsg(str)};
    if(flag == "wsh")  console.log = function(str){null;};
    if(flag == "sakura")  console.log = function(str){null;};
    if(flag == "wsh")  console.dir = function(str){null;};
    if(flag == "sakura")  console.dir = function(str){null;};
  }
}

// pretend process.exit
if(typeof(process) === "undefined"){
  if(flag == "wsh")  process={exit : function(e){WScript.Quit(e)}};
  if(debug_mode){
    if(flag == "sakura")  process={exit : function(e){Editor.TraceOut('done')}};
  }else{
    if(flag == "sakura")  process={exit : function(e){'done'}};
  }
}

// local functions
// 
var get_target = function(expandParam){
  // $F : opened file's full path
  // $f : opened file's name
  // $e : opened file's folder path
  // $b : opened file's extention
  // $C : 選択中の場合、選択テキストの1行目のテキスト(改行コード除く)
  //      選択中でない場合、カーソル位置の単語
  // 引数無し : 選択されている場合、選択された文字列。
  //       選択されていない場合、Clipboardにある文字列
  // $Z : 独自expandPrameter : 全テキスト
  // $L : 独自expandPrameter : 行選択として取得
  var ret ='';
  if(typeof(expandParam) === 'undefined'){
    if(Editor.IsTextSelected){
      ret = Editor.GetSelectedString(0);
    }else{
      ret = Editor.GetClipboard(0);
    }
  } else {
    if(expandParam === '$Z'){
      Editor.SelectAll();
      ret = Editor.GetSelectedString(0);
      Editor.IsTextSelectingLock(0);
      Editor.ExpandParameter(expandParam)
    } else if (expandParam === '$L'){
      if(Editor.IsTextSelected){
        // line select
        var lineNum = get_seletedLineNumber();
        ret = get_lines(lineNum.start_line_num, lineNum.end_line_num);
        console.dir(lineNum);
        console.log('L186 :' + ret);
        select_lines(lineNum.start_line_num, lineNum.end_line_num);
      }
    } else {
      ret = Editor.ExpandParameter(expandParam)
    }
  }
  return ret;
};

var get_seletedLineNumber = function(){
  var start_line_num = Editor.GetSelectLineFrom();
  var end_line_num = Editor.GetSelectLineTo() - 1;
  return {
    "start_line_num" : start_line_num,
    "end_line_num" : end_line_num
  }
}

var get_lines = function(start_line_num, end_line_num){
  if(typeof end_line_num === 'undefined'){
    end_line_num = Editor.GetLineCount(0);
  }
  if(typeof start_line_num === 'undefined'){
    start_line_num = 1;
  }
  Editor.Jump(start_line_num);
  Editor.GoLineTop(1);
  Editor.BeginSelect();
  Editor.Jump(end_line_num);
  Editor.GoLineEnd(0);
  var lines = Editor.GetSelectedString(0);
  console.log('L218 :' + start_line_num);
  console.log('L219 :' + end_line_num);
  Editor.CancelMode();
  return lines;
}

var select_lines = function(start_line_num, end_line_num){
  Editor.CancelMode();
  Editor.TextWrapMethod(0);
  Editor.Jump(start_line_num);
  Editor.GoLineTop(1);
  Editor.BeginSelect(0);
  Editor.Jump(end_line_num);
  Editor.GoLineEnd();
  // Editor.TextWrapMethod(2);
}

var get_template = function(herestrings, sep){
  sep = sep || '\r\n';
  var template = herestrings.toString().split(sep).slice(2,-2).join(sep);
  return template;
}

var show_menu = function(isDisplay){
  if(typeof(isDisplay) === 'undefined') isDisplay = true;
  var ope = 0;
  var menu_statement = function(){
/**
1. comment (&c),
2. comment in (&i),
*/
  }
  if(isDisplay){
    var menu_ = get_template(menu_statement)
    ope = Editor.CreateMenu( 1, menu_);
    // console.log(menu_statement);
    // console.log(ope);
    return ope;
  } else {
    return ope;
  }
}

var output_display = function(str){
  if(Editor.isTextSelected){
    Editor.InsText(str);
  } else {
    Editor.SetClipboard(0,str)
    Editor.TraceOut(str);
  }
}

var containsArray = function(ary, obj) {
    var len = ary.length;
    for (var i = 0; i < len ; i++) {
       //console.log('L273 :' + ary[i] + ' & ' + obj)
       if (ary[i] == obj) {
         return true;
       }
    }
    return false;
}

var get_commentString = function(ext){
  var comment_string = CONFIG.CONS_QUOTE_STRING;
  ext = ext.toLowerCase();
  //console.log('L284 : ' + ext);
  var file_name = Editor.ExpandParameter('$f');
  if (file_name.match(/^hosts$/i)) {
    comment_string = CONFIG.CONS_COMMENT_SHARP;
  } else {
    var len = CONFIG.CONS_COMMENT_SET.length;
    for(var i = 0; i < len; i++){
      if(containsArray(CONFIG.CONS_TARGET_SET[i], ext)){
        comment_string = CONFIG.CONS_COMMENT_SET[i];
        break;
      }
    }
  }
  return comment_string;
}

var put_comment = function(str, comment_string, line_code) {
  if(typeof line_code === 'undefined') line_code = "\r\n";
  Editor.TextWrapMethod(0);
  var formatted = '';
  str = StringUtil.unifyLineCode(str, line_code);
  str = StringUtil.tabToSpace(str, 2);
  var ary = str.split(line_code);
  var indent_len = 0;
  var ary_buf = [];
  
  var len = ary.length;
  for (var i = 0; i < len; i++){
    var regx = new RegExp("^\\s*","m");
    regx.exec(ary[i]);
    var lastMatch_ = RegExp.lastMatch;
    if(i == 0) indent_len = lastMatch_.length;
    indent_len = indent_len < lastMatch_.length ? indent_len: lastMatch_.length;
  }
  
  var indent_string = StringUtil.repeat(' ', indent_len);
  for (var i = 0; i < len; i++){
    var regx_target = new RegExp('^' + indent_string);
    regx_target.exec(ary[i]);
    var lastMatch_ = RegExp.lastMatch;
    // WScript.Echo('lastMatch_ = "' + lastMatch_ + '"');
    var rightContext_ = RegExp.rightContext;
    ary_buf.push(lastMatch_ + comment_string + rightContext_);
  }
  
  formatted = ary_buf.join(line_code);
  return formatted;
}

var remove_comment = function(str, comment_string, line_code) {
  if(typeof line_code === 'undefined') line_code = "\r\n";
  Editor.TextWrapMethod(0);
  var formatted = '';
  str = StringUtil.unifyLineCode(str,line_code);
  str = StringUtil.tabToSpace(str, 2);
  var ary = str.split(line_code);
  var indent_len = 0;
  var ary_buf = [];
  
  var len = ary.length;
  for (var i = 0; i < len; i++){
    ary[i] = ary[i].replace(/(\/\/)([\w"']+)(.*)/gm,"$1 $2$3"); //'"
    var regx = new RegExp("^\\s*","m");
    regx.exec(ary[i]);
    var lastMatch_ = RegExp.lastMatch;
    if(i == 0) indent_len = lastMatch_.length;
    indent_len = indent_len < lastMatch_.length ? indent_len: lastMatch_.length;
  }
  
  var indent_string = StringUtil.repeat(' ', indent_len);
  for (var i = 0; i < len; i++){
    ary[i] = ary[i].replace(/(\/\/)(\w+)(.*)/gm,"$1 $2$3");
    var regx_target = new RegExp("^" + indent_string + comment_string,"gm");
    if(regx_target.test(ary[i])){
      regx_target.exec(ary[i]);
      var rightContext_ = RegExp.rightContext;
      ary_buf.push(indent_string + rightContext_); 
    } else {
      ary_buf.push(ary[i]); 
    }
    console.log('L377 :' + ary[i]);
    console.log('L378 :' + ary_buf[i]);
  }
  
  formatted = ary_buf.join(line_code);
  return formatted;
}

// do process   --------------------------------------------------
//
var doProcess = function(menuSelected){
  console.log('------------------------- start //');
  console.log('APP : ' + CONFIG.APP_NAME);
  Editor.TextWrapMethod(0);
  var target_ = get_target('$L');
  var ext =  get_target('$b');
  var comment_string = get_commentString(ext);
  var formatted = '';
  // pre-process
  var ope = 0;
  if(!menuSelected){
    ope = show_menu();
  } else {
    ope = menuSelected;
  }
  // main process for selected menu's one
  if(ope == 1){
    //1. comment (&c),
    var formatted = put_comment(target_, comment_string);
  }
  if(ope == 2){
    //2. comment in (&i),
    var formatted = remove_comment(target_, comment_string);
  }
  // post-process 
  if(ope !== 0){
    output_display(formatted);
  }
  Editor.TextWrapMethod(2);
  // for debug
  if(debug_mode){
    console.log('ope = ' + ope);
    console.log('comment_string = ' + comment_string);
    console.log('target_  = ' + target_);
    console.log('formatted = ' + formatted);
  }
}

// ------------------------------------------------ entry point
// 
if(typeof(Editor) !== 'undefined'){
  // Export Library
  var StringUtil = exports.StringUtil;
  process.exit(doProcess());
} else {
  if(typeof(WScript) !== 'undefined'){
    WScript.Echo('[Warn] Opps! Sorry. This app is for Sakura Ediotr.');
  } else {
    console.log('[Warn] Opps! Sorry. This app is for Sakura Ediotr.');
  }
}

}())

// NOTICE:JSON記述が正しくないとevalでエラーとなり、CONFIGを読み込めない
var CONFIG = {
  "DEBUG_MODE": false,
  "APP_NAME": "./app_commentInOut.jse"
}

CONFIG.CONS_QUOTE_STRING = '> ';
CONFIG.CONS_COMMENT_SLASH = '// ';
CONFIG.CONS_TARGET_SLASH = ['cs', 'cpp', 'java', 'js', 'jse'];
CONFIG.CONS_COMMENT_SHARP = '# ';
CONFIG.CONS_TARGET_SHARP = ['ini', 'ps1', 'psd1', 'ts', 'py', 'pl', 'rb', 'php', 'coffee'];
CONFIG.CONS_COMMENT_SEMICOLON = '; ';
CONFIG.CONS_TARGET_SEMICOLON = ['bat', 'cmd', 'ahk'];
CONFIG.CONS_COMMENT_QUATATION = "' ";
CONFIG.CONS_TARGET_QUATATION = ['vb', 'vbs'];
CONFIG.CONS_COMMENT_HYPHEN = "-- ";
CONFIG.CONS_TARGET_HYPHEN = ['sql', 'plsql'];
CONFIG.CONS_COMMENT_PERCENT = "% ";
CONFIG.CONS_TARGET_PERCENT = ['tex'];

CONFIG.CONS_COMMENT_SET = [
  CONFIG.CONS_COMMENT_SLASH,
  CONFIG.CONS_COMMENT_SHARP,
  CONFIG.CONS_COMMENT_SEMICOLON,
  CONFIG.CONS_COMMENT_QUATATION,
  CONFIG.CONS_COMMENT_HYPHEN,
  CONFIG.CONS_COMMENT_PERCENT
];

CONFIG.CONS_TARGET_SET = [
  CONFIG.CONS_TARGET_SLASH,
  CONFIG.CONS_TARGET_SHARP,
  CONFIG.CONS_TARGET_SEMICOLON,
  CONFIG.CONS_TARGET_QUATATION,
  CONFIG.CONS_TARGET_HYPHEN,
  CONFIG.CONS_TARGET_PERCENT
];