選択範囲のURL・パスを開く

提供: MeryWiki
移動先: 案内検索

「ひらけゴマ!」[編集]

(最終更新 2019/04/07)

  • 日本語URL」など、禁止文字を含むために Mery が正しい URL として認識せず、ダブルクリックやコンテキストメニューの「URLを開く」コマンドでは開けない URL 文字列を 既定のブラウザで 開きます(http:// か https:// が先頭にあるもののみ)。
  • 「mailto:」が付いていないメールアドレスも 既定のメールクライアント で開きます。
  • 文字列がファイルやフォルダのパスであればこれも 既定のプログラム で開きます。
環境変数 で省略されたパスや 相対パス を補完して開くことができるので、「ファイル名を指定して実行」(Win+R) にちかい感覚で使用できます。
  • 既定のプログラム以外 でファイルを開きたい場合
プログラムのパス"␣ファイルのパス
のかたちであれば指定したプログラムで開けます。
"プログラムのパス"(ダブルクォートで囲うこと) +半角スペース+ ファイルのパス(必要であればダブルクォートで囲う)
というかたちの文字列は、コマンドラインとして引数つきで処理します。


複数行 にリストアップした URL やパスを一括で開いたり、登録済みの特定の "キーワード" を範囲選択して実行することで「お気に入り」の URL やパスを開いたりできますので、Mery を簡易的な テキストランチャ として使用できます。

  • URL やファイルパス、「お気に入りの "キーワード"」として処理できない行は無視します。
  • 選択範囲がないときは、キャレットのある行全体の文字列を処理します。
  • URL やファイルパスなどの文字列が カッコ空白文字 で囲われていたり、行頭に 箇条書きの記号(ビュレット)や 行コメント のコメントマークがついている場合、これらを除いた文字列を URL/パス として開きます。


  • Mery の「ファイルから検索」の検索結果一覧にリストアップされた「ファイル名(行番号):」形式の文字列
C:\Program Files\Mery\Mery.txt(200):
からファイルを開く「ファイルへ移動」コマンドの機能を追加しました。
この「開けゴマ!」マクロでは、選択範囲に含まれる複数行のファイルパスを (行番号,桁) 指定つきでいっぺんに開けます。


その他、詳細な仕様についてはソースコード内の /** コメントドキュメント */ の部分を参照してください。


ソースコード[編集]

ダウンロード[編集]

ファイル:選択範囲のURL・パスを開く.zip」(アイコン入り) 最終更新: 2019/04/07


仕様詳細(コメントドキュメント)[編集]

>> コメントドキュメント部分をスキップ
#title = "選択範囲のURL/パスを開く"
#tooltip = "選択範囲のURLやパスを既定のプログラムで開く"
#icon = "run_with[1].ico"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",40

/**
 * ※選択範囲や行の先頭の「 // 」「;」などの行コメント記号、
 *  「・」「*」などの箇条書き記号、および「●」「◆」などの記号は、
 *   行頭/行末の空白文字や禁止文字 <> とあわせて除去したうえで処理します。(2019/03/15 追加)
 *     =-⁃・・•◦‣○●■◆▼▲※→⇒〜~†*:;#' 
 *
 *  ・カレントフォルダ/相対パス/代替 PATH にあるフォルダ/ファイルで
 *    ファイル名の先頭に除去対象の記号があるとフォルダ名/ファイル名だけでは開かなくなります。
 *      e.g.  "●FolderName"  は不可  → フルパス(絶対パス)や  ".\◆FolderName"  は可
 *  ・お気に入りのキーワードの先頭に除去対象の記号を使用しないで下さい。
 *  ・「 // 」ではじまるネットワークパス  //Android/shared/  は開きません。
 *    → \\Android\shared\  は可(…多分)
 *
 * ※選択範囲や行全体が対になる1組のカッコで囲われている場合、
 *   カッコを除去できます。(2019/03/15 追加)
 *
 * ①: Mery では  " < >  以外にも  ! ' ( ) * [ ] ^ ` { | }  が URL 用文字から除外されていますが、
 *   これらの文字をふくむためにエディタ上で正しいハイパーリンクになっていない URL 文字列でも
 *   既定のブラウザで開きます。
 *
 *   ※文字列を「 " " 」で囲って丸投げするだけなので、URL エンコードはブラウザ任せです。
 *     「日本語URL」も既定のブラウザに送りますが、対応できるかはブラウザ側の仕様に依存します。
 *   ※行頭から http:// までの文字列は無視しますが、 URL の後ろに続く文字列は除去しません。
 *   ※開けるのは先頭に http:// か https:// がついた URL 文字列のみです。
 *     www.example.com/hoge/ のような http:// が省略された文字列には対応しません。
 *
 * ②: メールアドレスなら既定のメールクライアントでメッセージを新規作成します。
 *
 *   ※mailto: の有無によらずにメールアドレス文字列を開きます。
 *   ※メールアドレスとおなじ名前のフォルダを相対パスや PATH 略記のパスとして優先的に開きたい場合は、
 *     ② のコードを下位(⑩の上)に移動させてください。
 *   ※メールアドレスの判定基準は「メールアドレス 正規表現」で検索トップにあったサイトからの拾い物です。
 *     ref. 『メールアドレスを表す現実的な正規表現 - Qiita』
 *     https://qiita.com/sakuro/items/1eaa307609ceaaf51123
 *
 * ⓪: Mery の「ファイルへ移動」コマンド用の (行,桁) 番号指定つきフルパスの書式
 *     C:\Program Files\Mery\Mery.txt(2,5)
 *   でファイルの実在確認ができるものは、行・桁 指定のコマンドラインに置換し
 *     "Mery.exe" /l 2 /cl 5 "C:\Program Files\Mery\Mery.txt"
 *   実行中の Mery のプロセスで開きます。(2019/03/15 追加)
 *
 *   ※実在するファイルでも「拡張子に (カッコ) が含まれている」など
 *     拡張子と規定のプログラムのヒモづけが定義されていないものは
 *     WScript.Shell.Run() がエラーを返し開けないようなので
 *     ( Win+R の「ファイル名を指定して開く」では開ける)、
 *     この「Mery で開く」コードを ③ の "フルパスを開く" コードよりも先に処理します。
 *
 * ③: 選択範囲の文字列がファイルやフォルダのフルパスなら、実在確認して既定のプログラムで実行します
 *    (環境変数を %PATH% 形式で短縮したパスも展開し、実在確認をして既定のプログラムで実行します)。
 *     ネットワークフォルダの \\パス も、実在確認をして既定のプログラムで実行します。
 *
 *   ※「 // 」か「 \\ 」ではじまる行を選択範囲に含めると、ネットワークフォルダの実在確認を試行するため
 *    検索に時間がかかります(「 // 」か「 \\ 」の直後が空白文字や禁止文字なら ③ をスキップします)。
 *    → 先頭の「 // 」を除去するコードを追加(2019/03/11)
 *   ※フルパスでない文字列でも FileSystemObject が勝手に相対パスや PATH を補完して
 *     ③ のメソッドで開くことがあるようでます。
 *
 * ④: 環境変数を %PATH% 形式で短縮したパスの場合は、省略された拡張子も補完します。
 *   ※実行ファイルに引数を渡す場合は、パスを「 " " 」で囲ってください(後述)。
 *
 * ⑤~⑦: アクティブなドキュメントのカレントディレクトリからの相対パスとして
 *   ファイルやフォルダの実在確認ができるなら、既定のプログラムで実行します。
 *
 *   ※処理できる相対パスの形式は、
 *     ⑤: 先頭だけに  ..\  または  .../  が付いたものか(拡張子を補完しない)
 *     ⑥: カレントディレクトリまでのパスを完全に省略したもののみで、
 *     パスの途中にも  .\  などがあるものは処理しません。
 *     ⑦: ⑥のパターンにたいして、省略された拡張子を補完します。
 *
 * ⑧: システム環境変数 PATH を省略したパスを補完し、実在確認をして既定のプログラムで実行します。
 * ⑨: 拡張子 PathExt が省略されたものも、定義配列から実在確認を試行して実行します。
 *
 *   ※WScript.Shell.Run() は本来 PATH や PathExt (および App Paths)を補完して実行させられますが
 *     実在確認してから実行させないとマクロのエラーとして扱われてしまうので、
 *     ⑧, ⑨ で処理するシステム環境変数 PATH は、定義配列に手動で列挙したもののみとします。
 *   ※パスのとおった App Paths も、Path の定義配列に親フォルダのパスを手動で追加しないと処理しません
 *     (App Paths はプログラムのインストーラがレジストリに書き込んだ PATH の代用機能です。
 *       配下のレジストリキー名で実行するとキーの配下に記述されたプログラムを起動できます)。
 *     [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths]
 *
 * ⑩: file://~ への絶対パスを既定のプログラムで実行します。
 *
 *   ※先頭の "file://" を外しローカルファイルとして実在確認をしてから
 *     ドライブ名以降のパスを WScript.Shell.Run() に投げて実行させます。
 *     ⑩ のメソッドはネットワークドライブのファイル/フォルダには対応しません。
 *
 * ⑪: なんでもいいから WScript.Shell.Run() に投げて実行させます。
 *     shell:コマンドなどパスのかたちを取っていないものはこれでしか実行できませんが、ミスタイプや
 *     ファイルやフォルダが実在しない場合にはマクロのエラーとして扱われるので「●非推奨」です。
 *   ※設定変数により ⑪ のコードは初期状態で無効化してあります。
 *
 * ▼ 共通 ▼
 *   ※※※ 基本的に範囲選択して実行する前提です ※※※
 *
 * ・範囲選択なしのときは、アクティブな論理行の文字列を取得して URL/パス を実行します。
 *   選択範囲や各行の先頭/末尾の「空白文字」「 <> 」は無視します。
 *
 * ・複数行の各行にひとつずつ列挙された URL/パス それぞれを既定のプログラムで実行することができます。
 *   箇条書きの行であれば行頭記号をはずして URL/パス を開きます。
 *
 * ・①=URL、②=メールアドレス、⑪=強制執行は、実在確認なしで実行します、
 *   ⓪, ③~⑨=ローカルファイル/フォルダのパスは、実在確認して実行します。
 * ・%PATH% 形式で略記されたパスは、展開してから実在確認して実行します。
 *
 * ・すべて WScript.Shell.Run() での起動処理なので、ファイル/フォルダの実在確認ができても
 *   イレギュラーなファイル名や拡張子の場合は開けないことがあります。
 *     e.g. c:\hoge\fuga.h(1)  ← 規定のプログラムが定義されていない拡張子
 *
 * ・選択範囲や各行内の先頭に「 " " 」で囲われた部分があれば、
 *   「 " ~ " 」をパス(コマンド)と見做し、
 *   「 " ~ " 」より後ろの文字列を引数(コマンドラインオプション)として処理します。
 *
 *   ※※※ 基本的に引数つきのコマンドラインを処理する前提ではありません ※※※
 *
 *   選択範囲の先頭に「 " " 」で囲われた部分がない場合は、引数付きのコマンドであっても実行しません
 *   (※パスの中に半角スペースがあっても「 " "  」なしで開けることを優先するための仕様です)。
 *
 *   引数部分の「 " "  」の有無は考慮せず、WScript.Shell.Run() にそのまま渡します。
 *   引数部分が環境変数 Path, PathExt でディレクトリパスや拡張子を省略されていても
 *   マクロでは補完処理しません(環境変数 Path, PathExt の代替定義用の配列も適用しません)。
 *   引数部分は実在確認しないので、 %PATH% も展開しないでそのまま渡します。
 *
 * ・選択範囲の文字列の先頭が「 " 」でそれを閉じる「 " 」の位置が不適切(または閉じる「 " 」がない)場合、
 *   ⑧ のコードにより代替 PATH 配列内の最初のフォルダが開くようです。
 *   (→ 2019/03/15 「空行をスキップ」 のコードで阻止)
 *
 * ・選択範囲の文字列がドット「 . 」だけで実行すると
 *   ⑥ のコードによりアクティブなドキュメントの「カレントフォルダ(親フォルダ)」が開きます…。
 *   「 .. 」ならその親フォルダが開くので、WScript.Shell.Run() が相対パスとして処理しているようです。
 *   (これもこれで面白いので、あえてデバッグしないで残しておきます)
 *
 * ・拡張子 PathExt の補完は、④, ⑦, ⑨ の場合のみとします。
 *
 * ・「お気に入り」の URL やパスを特定の「キーワード」で開くこともできます。
 * ・「省略可能なフォルダパス」配下のフォルダ/ファイルは、
 *   「フォルダ名」や「ファイル名」だけで開けます(※代替 PATH 機能)。
 *
 * 以下のような 文字列/論理行 を開くことができます
 *(※ 行頭/行末の空白は無視し、無効な行はスキップします)。


▼ 日本語や半角スペースなどの禁止文字を含む URL(http:// があるもののみ) ▼

  "https://www.haijin-boys.com/wiki/よくある質問#.E6.97.A5.E6.9C.AC.E8.AA.9E.E3.82.92.E5.90.AB.E3.82.80_URL_.E3.82.92.E8.AA.8D.E8.AD.98.E3.81.97.E3.81.9F.E3.81.84"  
  https://www.haijin-boys.com/wiki/マクロリファレンス:Selection インターフェイス

▼ メールアドレス(mailto: あり/なし) ▼

  < hogehoge@example.com >  

▼ ファイル/フォルダパス(絶対パス:フルパス) ▼

  C:\Program Files	
  "c:\windows\system32\notepad.exe"  
  [ C:\Program Files\Mery\Mery.txt ]

▼ アクティブなドキュメントからの相対パス(..\ 形式の場合は、要 拡張子) ▼

  "連続する重複行を削除"	
  ..\Mery.ini 

▼ 環境変数で短縮/省略されたパスやコマンドライン ▼

  %PROGRAMFILES%\internet explorer\iexplore
  "calc"	
  cmd
  (regedit)
  "notepad" "%PROGRAMFILES%\Mery\Mery.txt"
  "explorer" /select, %USERPROFILE%\ntuser.ini

▼ インターネットアドレス形式のパスやネットワークパス、[●shell:コマンド ←非推奨(※実在確認なし)]  ▼

  file:///c:/boot.ini  
  \\Android\shared
  shell:Desktop 

▼ 行頭に箇条書きの記号や行コメントの記号がある URL/パス ▼

  ・eula.rtf
// https://www.haijin-boys.com/software/mery/

▼ Mery フォルダにショートカットファイルを置くと、「無題」ドキュメント上の「ショートカット名の文字列」で起動できる ▼
▼ または ※代替 PATH 配列※ のフォルダにショートカットファイルを置くと、すべてのドキュメント上の「ショートカット名の文字列」で起動できる ▼

  "foobar2000.exe - ショートカット"

 *
 */

設定項目[編集]

>> 設定項目をスキップ
var start = new Date();	// 所要時間計測(開始)

// ---------- ▼ 設定項目 ▼ ----------

// ■ 対になるカッコで囲われていたらカッコを除去する? ■ 
var removeBracketsEnable = true;

// ▼ 対になるカッコの種類 ▼
// \"\" はコマンドライン用に必要なので含めないこと! e.g. "notepad" "%PROGRAMFILES%\Mery\Mery.txt"
var brackets = "()「」<>[][]{}''()「」『』<>[]{}【】〖〗﹁﹂﹃﹄︵︶︿﹀︽︾︹︺︷︸︻︼︗︘⦅⦆⦅⦆〚〛〔〕〘〙〈〉《》””’’〝〟‘’“”――~~〜〜";


// ■ 「お気に入り(特定のキーワード)」を実行可能な URL/パス に変換する ■
var favoritesEnable = true;

// ▼ 「お気に入り」の URL/パス とキーワードを登録 ▼
// \ は2つ重ね \\ にすること
// Array( [ ] , [ ] , [ ] ); となるよう、 [ ] や ,カンマ の漏れがないように!

var favorites = new Array(
//[ "URL または パス", "キーワード1", "キーワード2" ], 

  [ "https://www.haijin-boys.com/", "blog", "ブログ" ], 
  [ "https://www.haijin-boys.com/wiki/メインページ", "wiki", "ウィキ" ], 
  [ "https://www.haijin-boys.com/wiki/マクロライブラリ", "マクロライブラリ", "ライブラリ" ], 
  [ "https://www.haijin-boys.com/wiki/マクロリファレンス", "マクロリファレンス", "リファレンス" ], 
  [ '"notepad" "' + editor.FullName.replace( /mery\.exe$/i , "mery.ini" ) + '"', "ini", "INI" ], 	// Mery.ini をメモ帳で開く
  [ editor.FullName.replace( /mery\.exe$/i , "mery.txt" ), "readme" ], 
  [ "%USERPROFILE%\\desktop" , "desktop", "デスクトップ" ], 
  // [ "(※eメールクライアントのパス)" , "(※自分のeメールアドレス)" ], 
  // [ "" , "" ], 
  // [ "" , "" ], 
  // [ "" , "" ], 
"" );	// new Array() を閉じ


// カレントフォルダはアクティブなドキュメントの親フォルダ
// ■ 「無題」のドキュメントの場合は Mery の実行フォルダ ■(変更する場合は末尾に \\ をつける)
var $parentFolder = document.FullName ? document.Path
                                      : editor.FullName.replace( /mery\.exe$/i , "" );


// ■ 省略可能なフォルダパスの 環境変数 PATH の代わりに ■
// \ は2つ重ね \\ にすること (前に置いたものが優先)
// ショートカットファイルを集めたフォルダを登録すると、ショートカットのベース名で実行できるようになる
// (ショートカットのベース名を1~3文字ぐらいにするととても便利)
var $envPathArray = new Array(
  editor.FullName.replace( /\\mery\.exe$/i , "" ) ,		// Mery フォルダ
  editor.FullName.replace( /\\mery\.exe$/i , "\\macros" ) ,	// Mery\Macros フォルダ
  ScriptFullName.replace( RegExp( "\\" + ScriptName + "$" , "i" ) , "" ) ,	// このマクロの保存フォルダ
  "c:\\windows" , "c:\\windows\\system32" ,
"" );	// new Array() を閉じ


// ■ 省略可能な拡張子の環境変数 PathExt ■ (前に置いたものが優先)
// ※ ".CPL"(コントロールパネルアプレット)は不可 → ショートカットファイルを Path 配列にあるフォルダに置けば実行可
var $pathExtArray = new Array(
  ".LNK" , ".URL" ,		// リンク拡張子とインターネットショートカット拡張子
  ".COM" , ".EXE" , ".BAT" , ".CMD" , ".VBS" , ".VBE" , 
  ".JS", ".JSE" , ".WSH" , ".WSF" , ".MSC" , ".PSC1" , ".SCR"
);	// new Array() を閉じ


// ■ アウトプットバーに結果を表示する? ■ (デバッグログ用)
var outputEnable = false;


// ■ なんでもいいから WshSlell.Run() に投げる? ■ [非推奨] コード ⑪番 
// カレントフォルダ/PATH/App Paths/PathExt の補完で実行されるかもしれないが、それ以外は Mery のエラー(マクロのエラー)になる
var forceRunEnable = false;

// ---------- ▲ 設定項目 ここまで ▲ ----------

実行コード[編集]

// 「ひらけゴマ!!」

// ログ:日時を出力 YYYY-MM-DD hh:mm:ss.sss UTC+9000
// ログ:Go "Open Sesame !!"  >>  アクティブなドキュメントのパス
Output( DateTime_ms( start ) + '\nGo "Open Sesame !!"  >>  '
      + ( document.FullName ? document.FullName : "「無題」ドキュメント" ) );

// 選択範囲がないときは論理行を選択
var s = document.selection;
var $str = s.IsEmpty ? document.GetLine( s.GetActivePointY( mePosLogical ), 0 )
                     : s.Text;

// 先頭行の行番号(論理行)
var ty = s.GetTopPointY( mePosLogical );
var by = s.GetBottomPointY( mePosLogical );

// 全体が空白文字列なら
if ( $str.match( /^[\s ]*$/g ) ) {
  // ログ:[#先頭行-#最終行] is Empty.
  Output( "[#" + ty + ( ty != by ? "-#" + by : "" ) + "] is Empty." );
}

// 行ごとのループ処理開始
else {
  var WshShell = new ActiveXObject( "WScript.Shell" );
  var Fso = new ActiveXObject( "Scripting.FileSystemObject" );

  // 選択範囲を各行ごとに開けるよう、論理行で分割して配列に
  var $strArray = $str.split( "\n" );


  perLineLoop:	// hit フラグを 0 にセット
  for ( var i = 0, hit = 0; i < $strArray.length; i ++ ) {

    // 論理行の番号を取得(デバッグログ用)	// [#行番号]
    if ( outputEnable ) {
      var $line = "[#" + ( ty + i ) + "] ";
    }

    // 各行の先頭/末尾の空白文字と < > を除去
    // ※「 " 」は除外した → コマンドライン判定に必要
    $strArray[i] = $strArray[i].replace( /^[\t  <>]*|[\t  <>]*$/g , "" );

    // 行コメントや箇条書きの行頭記号も除去(2019/03/15 追加)
    var st = $strArray[i].replace( /^[\t  ]*\/\/[\t  ]*|^[\t  <>=\-⁃・・•◦‣○●■◆▼▲※→⇒〜~†*:;#']*|[\t  <>]*$/g , "" );
    // ログ:[#行番号] ※ Remove bullets and comment-delimiters.
    if ( st.length != $strArray[i].length ) {
      Output( $line + "※ Remove bullets and comment-delimiters:  "
            + ( $strArray[i].slice( 0, - st.length ) ), 0 );
    }

    // 文字列全体が対になるカッコで囲われていたらカッコを除去する(2019/03/15 追加)
    if ( removeBracketsEnable ) {
      removeBracketsLoop:
      for ( var b = 0; b < brackets.length - 1; b ++ ) {
        if ( st.length > 1 && b % 2 == 0
            && st.charAt( 0 ) == brackets[ b ]
            && st.charAt( st.length - 1 ) == brackets[ b + 1 ] ) {
          st = st.slice( 1, st.length - 1 ).replace( /^[\t  ]*|[\t  ]*$/g , "" );
          // ログ:[#行番号] ※ Remove Brackets: 開きカッコ & 閉じカッコ
          Output( $line + "※ Remove brackets:  "
                + brackets[b] + "  &  " + brackets[b+1], 0 );
        }
      }
    }

    // 空行をスキップ
    if ( st.match( /^[\t  ]*$|^"[\t  ]*"?$/ ) ) {
      // ログ:[#行番号] × Empty Line.
      Output( $line + "× Empty Line.", 0 );
      continue perLineLoop;
    }


    // 選択範囲 (行) の文字列が特定のキーワードであれば「お気に入り」の URL/パス に変換する
    // ログ:[#行番号] ※ Favorite: "キーワード" >> URL/パス
    if ( favoritesEnable ) {
      st = ConvertFavorites( st );
    }


    // ① 文字列がURLなら既定のブラウザで開く(エンコードなし)
    if ( st.match( /"?https?:\/\/|"?ftp:\/\// ) ) {
      var $url = st.slice( st.search( /"?https?:\/\/|"?ftp:\/\// ) );

      WshShell.Run( '"' + $url.replace( /^"|"$/g , "" ) + '"' );
      // ログ:[#行番号] ① Open Link: URL
      Output( $line + "① Open Link:  " + $url , 1 );
      continue perLineLoop;
    }	// end ①


    // ② 文字列がメールアドレスなら既定のメールクライアントで開く(エンコードなし)
    if ( ! st.match( /(?:\:\/|\:\\)/ ) && st.length < 255
        && st.match( /[:  \t]*?[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]{1,64}@[a-zA-Z0-9-]{1,63}(?:\.[a-zA-Z0-9-]+)*$/ ) )
    {
      var $mail = st.replace( /^.*?[:  \t]*?([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]{1,64}@[a-zA-Z0-9-]{1,63}(?:\.[a-zA-Z0-9-]+)*).*$/ , "$1" );

      WshShell.Run( "mailto:" + $mail.replace( /^"|"$|^mailto:/g , "" ) )
      // ログ:[#行番号] ② Open: メールアドレス
      Output( $line + '② Open:  "mailto:'
            + st.replace( /^"|"$|^mailto:/g , "" ) + '"' , 1 );
      continue perLineLoop;
    }	// end ②


    // ファイル名の禁止文字だけの文字列はスキップ
    // ※ 「"」を含めると「"」1文字でカレントフォルダは開かなくなる
    if ( st.match( /^[\s \\/:,;*?<>|]*$/ ) ) {
      // ログ:[#行番号] ③' Bad character(s): 文字列
      Output( $line + "③'Bad character(s):  " + st );
      continue perLineLoop;
    }


    // ⓪ ファイルパス+(行,桁) 形式なら Mery で開く (2019/03/15 追加)
    if ( st.match( /^[a-z]\:\\/i ) && st.match( /\(\d+(?:,\d+)?\)[:]?$/ ) ) {
      var $file = st.replace( /^(.+)\(\d+(?:,\d+)?\)[:]?$/ , "$1" );
      var $line_Num = st.replace( /^.+\((\d+)(?:,\d+)?\)[:]?$/ , "$1" );
      var $column_Num = st.replace( /^.+\(\d+,(\d+)\)[:]?$/ , "$1" );
      if ( Fso.FileExists( $file ) ) {
        // コマンドライ用文字列 "Mery.exe" /l yy /cl xx "filepath" に置換
        var $meryCommandline = '"' +  editor.FullName 
                             + '" /l ' + $line_Num 
                             + ( $column_Num ? ( ' /cl ' + $column_Num ) : "" )
                             + ' "' + $file + '"';
        WshShell.Run( $meryCommandline );
        // ログ:[#行番号] ⓪ Open with Mery: コマンドライン文字列
        Output( $line + "⓪ Open /w Mery:  " + $meryCommandline , 1 );
        continue perLineLoop;
      }
    }	// end ⓪


    var $command, $command_Op, $isExpanded;
    // 文字列の先頭に "" で囲われている部分があれば、"コマンド" と 引数 として分離する
    // "コマンド" 部分の環境変数 %PATH% はフルパスに展開する
    if ( st.match( /^"/ ) && st.substr( 1 ).search( /"(?=\s|$)/ ) ) {
      var $secondWQuoteID = st.substr( 1 ).search( /"/ );
      $command = WshShell.ExpandEnvironmentStrings( st.substr( 1, $secondWQuoteID ) );
      $command_Op = " " + st.substr( 2 + $secondWQuoteID ).replace( /^\s*/ , "" );
    }
    else {
      $command = WshShell.ExpandEnvironmentStrings( st );
      $command_Op = "";
    }
    // 文字列中の %PATH% を展開した場合のフラグ(先頭3文字を比較)
    if ( st.match( /%/ ) && $command.substr( 0, 3 ) != st.replace( /^"/ , "" ).substr( 0, 3 ) )
    {
      $isExpanded = true;
      // ログ:[#行番号] ※ Expand: 文字列 >> "コマンド" 引数
      Output( $line + "※ Expand:  " + st + "  >>  " + $command + $command_Op, 0 );
    }
    // 以下、フォルダ/ファイルの実在確認は $command にたいしておこなう


    // ③ 文字列が ファイル/フォルダ パスなら既定のプログラムで開く(実在確認して実行)
    if ( ! $command.match( /^[^.]\.+[\\/]|^[\\/]{2}[\s:,;*?<>|]|^\.+\s*$/ )
        && ( Fso.FolderExists( $command ) || Fso.FileExists( $command ) ) )
    {
      WshShell.Run( '"' + Fso.GetAbsolutePathName( $command ) + '"' + $command_Op );
      // ログ:[#行番号] ③ Open File / Folder: "コマンド" 引数
      Output( $line + '③ Open File / Folder:  "'
            + Fso.GetAbsolutePathName( $command ) + '"' + $command_Op , 1 );
      continue perLineLoop;
    }	// end ③


    // ④ %PATH% 形式の短縮パスで拡張子も省略されている場合(実在確認して実行)
    if ( $isExpanded ) {
      percentPathExtLoop:
      for ( var j = 0; j < $pathExtArray.length; j ++ ) {
        var $percentPathExt = ( $command + $pathExtArray[j] );
        if ( Fso.FileExists( $percentPathExt ) ) {
          WshShell.Run( '"' + $percentPathExt + '"' + $command_Op );
          // ログ:[#行番号] ④ Open File / Folder + .EXT: "コマンド.EXT" 引数
          Output( $line + '④ Open File / Folder + .EXT:  "'
                + $percentPathExt + '"' + $command_Op , 1 );
          continue perLineLoop;
        }
      }
    }	// end ④


    var $relativePath;
    // ⑤ 文字列が  ..\相対パス  または  ../相対パス  の場合(実在確認して実行)
    // ※ 先頭以外に .\ や ./ があるものは不可
    if ( $command.match( /^\.+(?:[\\/])/ )	// ( /^\.+(?:[\\/][^\\/:,;"*?<>|]+)+/ )
        && ! $command.match( /(?:[\\/]{2,}|^[^.]+\.+[\\/])/ ) )
    {
      // 「.」の数で親フォルダから階層をさかのぼる
      var $dotCount = $command.search( /[\\/]/ );
      var $pathArray = $parentFolder.replace( /\\/g , "/" ).split( "/" );
      for( var j = 0; j < $dotCount; j ++ ) {
        $pathArray.pop();
      }
      $relativePath = $pathArray.join( "\\" ) + $command.replace( /^\.+/ , "" );
      if ( Fso.FolderExists( $relativePath ) || Fso.FileExists( $relativePath ) )
      {
        WshShell.Run( '"' + $relativePath + '"' + $command_Op );
        // ログ:[#行番号] ⑤ Open as ..\ Relative path: "補完済み相対パス" 引数
        Output( $line + '⑤ Open as ..\\ Relative path:  "'
              + $relativePath + '"' + $command_Op , 1 );
        continue perLineLoop;
      }
    }	// end ⑤


    // ⑥ - ⑨ 文字列にドライブルートがない場合
    if ( ! $command.match( /^[a-z]:[\\/]/i )
        && ! $command.match( /(?:[\\/]{2,}|^\.+[\\/])/ ) )
    {
      $relativePath = $parentFolder + $command.replace( /^\\/ , "" );

      // ⑥ 文字列がカレントフォルダ内の相対パスの場合(実在確認して実行)
      if ( $relativePath.replace( /\\+$/ , "" ) != $parentFolder.replace( /\\+$/ , "" )
          && ( Fso.FolderExists( $relativePath ) || Fso.FileExists( $relativePath ) ) )
      {
        WshShell.Run( '"' + Fso.GetAbsolutePathName( $relativePath ) + '"' + $command_Op );
        // ログ:[#行番号] ⑥ Open as Relative path: "補完済み相対パス" 引数
        Output( $line + '⑥ Open as Relative path:  "'
              + Fso.GetAbsolutePathName( $relativePath ) + '"' + $command_Op , 1 );
        continue perLineLoop;
      }	// end ⑥


      // ⑦ 文字列がカレントフォルダ内の相対パス(拡張子なし)の場合(実在確認して実行)
      else {
        relativePathExtLoop:
        for ( var j = 0; j < $pathExtArray.length; j ++ ) {
          var $relativePathExt = ( $relativePath + $pathExtArray[j] );
          if ( Fso.FileExists( $relativePathExt ) ) {
            WshShell.Run( '"' + Fso.GetAbsolutePathName( $relativePathExt ) + '"' + $command_Op );
            // ログ:[#行番号] ⑦ Open as Relative path + .EXT: "補完済み相対パス" 引数
            Output( $line + '⑦ Open as Relative path + .EXT:  "'
                  + Fso.GetAbsolutePathName( $relativePathExt ) + '"' + $command_Op , 1 );
            continue perLineLoop;
          }
        }	// end ⑦
      }


      // ⑧ システム環境変数 PATH(代替 PATH の配列)を省略したパスなら
      sysEnvPathOuterLoop:
      for ( var k = 0; k < $envPathArray.length; k ++ ) {
        sysEnvPathInnerLoop:
        for ( var j = 0; j < $pathExtArray.length; j ++ ) {
          var $sysEnvPath = ( $envPathArray[k] + "\\" + $command.replace( /^\\/ , "" ) );

          if ( Fso.FolderExists( $sysEnvPath ) || Fso.FileExists( $sysEnvPath ) )
          {
            WshShell.Run( '"' + $sysEnvPath + '"' + $command_Op );
            // ログ:[#行番号] ⑧ Open sys PATH w/expand: "展開したフルパス" 引数
            Output( $line + '⑧ Open sys PATH w/expand:  "'
                  + $sysEnvPath + '"' + $command_Op , 1 );
            continue perLineLoop;
          }	// end ⑧


          // ⑨ 拡張子 PathExt とシステム環境変数 PATH を省略したパスなら
          if ( ! $command.match( /\\[^\\/:,;"*?<>|]+\.[^\\/:,;"*?<>|]+$/ ) ) {
            var $sysEnvPathExt = ( $sysEnvPath + $pathExtArray[j] );
            if ( Fso.FileExists( $sysEnvPathExt ) ) {
              WshShell.Run( '"' + $sysEnvPathExt + '"' + $command_Op );
              // ログ:[#行番号] ⑨ Open sys PATH w/expand + .EXT: "展開したフルパス.EXT" 引数
              Output( $line + '⑨ Open sys PATH w/expand + .EXT:  "'
                    + $sysEnvPathExt + '"' + $command_Op , 1 );
              continue perLineLoop;
            }
          }	// end ⑨
        }	// end sysEnvPathinnerLoop
      }	// end sysEnvPathOuterLoop
    }	// end ⑥ - ⑨


    // ⑩ 文字列が file:// ~ の場合(実在確認して実行)
    // ※ file:// 以降のドライブレターから後ろの部分で実在確認する
    if ( $command.match( /^file:\/\// ) ) {
      var $command_Test = CommandTest( $command, "file://" );
      if ( $command_Test ) {
        WshShell.Run( '"' + $command_Test + '"' + $command_Op );
        // ログ:[#行番号] ⑩ Open File / Folder on localhost: "フルパス" 引数
        Output( $line + '⑩ Open File / Folder on localhost:  "'
              + Fso.GetAbsolutePathName( $command_Test ) + '"' + $command_Op , 1 );
        continue perLineLoop;
      }
    }	// end ⑩


    // ⑪ なんでもいいからそのまま WScript.Shell.Run() に投げる
    // ※ 実在しないパスで強制実行すると、このマクロのエラー扱いになるので "非推奨"
    if ( forceRunEnable ) {	// 設定項目の変数
      WshShell.Run( $command + $command_Op );
    //WshShell.Run( '"' + $command + '"' + $command_Op );	// ← ダブルクオートで囲うなら
      // ログ:[#行番号] ⑪ Force Try: "コマンド" 引数
      Output( $line + "⑪ Force Try:  " +  $command +  $command_Op , 1 );
      continue perLineLoop;
    }	// end ⑪


    // 実在確認できない無効なパス
    else {
      // ログ:[#行番号] × Bad strings:  文字列
      Output( $line + "× Bad strings:  " + st );
      // continue perLineLoop;
    }

  }	// end perLineLoop
}	// end else (行ごとのループ処理)


// 処理終了時刻の取得と所要時間の計算
var end = new Date();
var elapsed = end.getTime() - start.getTime();
var elapsedStatus = "[ " + ( ( elapsed / 1000 ) + "000" ).replace( /(\.)(\d{3})(0*)/, "$1$2" ) + " sec. ]";

// ログ:elapsed: [ s.sss sec. ]
// ログ:'Finish "Close Sesame !!"
Output( "elapsed: " + elapsedStatus );
// Output( DateTime_ms( end ) );
Output( 'Finish "Close Sesame !!"\n' );

// ステータスバーに終了表示
if ( hit ) {
  Status = " Open Sesame! 。。。 " + hit + " hit(s)  "
         + elapsedStatus + "  " + DateTime_ms( end ).substr( 0, 19 );
  // Status = " Open Sesame!! ( " + hit + "件を実行 ) " + elapsedStatus + "  " + DateTime_ms( end ).substr( 0, 19 );
}
else {
  Status = " Open Sesame ... Fault!  "
         + elapsedStatus + "  " + DateTime_ms( end ).substr( 0, 19 );
  // Status = " URL / パス として開けませんでした。 " + elapsedStatus + "  " + DateTime_ms( end ).substr( 0, 19 );
}


// ------------------------------------------------------------

/**
 * 関数 Output( string, num )
 * アウトプットバーに結果を出力する
 */
function Output( str, num ) {
  if ( outputEnable ) {		// 出力許可フラグ
    OutputBar.Writeln( str );
  }
  if ( num ) {
    hit += num;			// ヒットフラグをインクリメント
  }
}

/**
 * 関数 ConvertFavorites( st )
 * お気に入り用のキーワードを URL/パス へ置換する
 */
function ConvertFavorites( str ) {
  var dist = str;
  Outer:
  for ( var j = 0; j < favorites.length; j ++ ) {
    if ( ! favorites[j] || ! favorites[j][0] ) {
      continue;
    }
    Inner:
    for ( var k = 1; k < favorites[j].length; k ++ ) {
      if ( ! favorites[j][k] ) {
        continue;
      }
      if ( favorites[j][k] == str ) {	// ヒットしたら
        dist = favorites[j][0];		// いちばん左の要素を返す
        // ログ:[#行番号] ※ Favorite: "キーワード" >> URL/パス
        Output( $line + '※ Favorite: ' + '"' + str + '"  >>  ' + dist );
        break Outer;
      }
    }	// end Inner loop [j][k]
  }	// end Outer loop [j]
  return dist;
}

/**
 * 関数 DateTime_ms( date )
 * 現在日時を日本時間  "YYYY-MM-DD hh:mm:ss.sss UTC+9000"  で返す(年月日の区切り: "-" )
 */
function DateTime_ms( d ) {
  if ( ! d ) {
    d = new Date();
  }
  var pad = function( str ) {
    return str.replace( /[0-9]+/g , function( $0 ) {
      return $0.length < 2 ? "0" + $0 : $0;
    } );
  }
  return d.getFullYear() + "-" + pad( ( d.getMonth() + 1 ) + "-" + d.getDate() +" " 
       + d.toLocaleTimeString() ) 
       + "." + ( d.getMilliseconds() + "000" ).substr( 0, 3 )
       + " UTC+0900";
}

/**
 * 関数 CommandTest( $command, "file://" )
 * "file:// ~" をローカルファイルとして実在確認する
 */
function CommandTest( str, scheme ) {
  // ドライブ名 "c:/" の部分があるかチェックして "c:/ ~ " のパスが実体があるか確認
  var $driveNameID = str.slice( scheme.length ).search( /[^.\\/]:[\\/]/ );
  if ( $driveNameID >= 0 ) {
    if ( Fso.FolderExists( str.slice( scheme.length + $driveNameID ) )
      || Fso.FileExists( str.slice( scheme.length + $driveNameID ) ) )
    {
      return str.slice( scheme.length + $driveNameID );
    }
  }
}

ソースコード先頭に移動

メモ[編集]


  • 2018/12/05 (sukemaru)
・一応、相対パスで記述した M3U プレイリストファイルからメディアファイルを開くことはできるようです。

  • 2018/12/08 (sukemaru)
・環境変数 PATH や PathExt を補完する代替 PATH 機能
・%PATH% の展開
・「お気に入り」の URL / パスの登録
・複数行にリストアップした URL やパスの一括処理
など、機能を追加してみましたがコードを整理できていません。
・環境変数 PATH の取得は自動化することもできますが、通常の使用では不要なものも多く、優先度(順番)も最適化されていないので手動で登録するかたちにしてあります。
・デバッグログ用にアウトプットバーへの出力コードが入ったままになっていますが、設定用の変数で無効化してあります。

  • 2018/12/09 (sukemaru)
・ダウンロードのリンク先を修正。
・コードのエラーを修正。

  • 2019/03/15 (sukemaru)
・⓪ Mery の「ファイルへ移動」コマンドの機能を移植。
・行頭記号を除去するコードを追加。
・カッコ囲いを除去するコードを追加(ON/OFF 選択可)。
・その他、不安定な挙動を修正。

  • 2019/04/07 (sukemaru)
・Quit() メソッドを削除


* ascii 文字
 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~


* Mery のエディタ上で URL として扱われる文字群(ascii)
[-\\0-9A-Z_a-z#$%+,./=?@~&:;]

http://example.com/#$%+,-./0123456789=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~&:;\


* Mery における URL の禁止文字群(ascii)
[ !"'()*<>\[\]^`{|}]

http://example.com/!"'()*<>[]^`{|}


* ファイル名の禁止文字
\ / : , ; " * ? < > |


ページの先頭に移動

スポンサーリンク