UWSCのヘルプを開くモジュール
以前、.chmファイルを解析してみた。
UWSCで.chmファイルを解析する - じゅんじゅんのきまぐれ
手元にあるUWSCインタープリターは、解析したキーワードを登録しておいて、hh.exeでヘルプを開くものでした。
が、これだと、キーワードを更新しないといけない。
それは面倒。
ということで、バージョンが上がる(または下がる)と、自動的にキーワードを更新して、ヘルプを開くモジュールを作成してみた。
使い方
モジュールをCALLして、Help.Open関数にキーワードを渡すだけ。
キーワードは前方一致(正規表現)なので、「A」を渡すと「A」で始まるキーワードの一覧を表示するので、選択するとそこを開く。(キーワードは大文字小文字無視)
前方一致ですが正規表現なので、「read」を含むにしたい場合「.*read」とかでOKです。
制約
CALLして使う場合、本体と同じフォルダーに存在すること。(キーワード更新の都合上)
テンポラリーフォルダーのパスに空白が含まれると、更新時におかしなことになる、、、かな。
特殊文字の記載は面倒になってやめました、、、。
スクリプト
help.uws
OPTION EXPLICIT, OPTFINALLY IFB GET_UWSC_NAME = "help.uws" THEN Help.UpdateKeywords() Help.Open(INPUT("keyword?")) ENDIF MODULE Help FUNCTION GetTempFolder(fso, sub=FALSE) RESULT = fso.GetSpecialFolder(2) IFB sub THEN DIM subp = RESULT + "\" + fso.GetTempName() WHILE fso.FolderExists(subp) OR fso.FileExists(subp) subp = RESULT + "\" + fso.GetTempName() WEND RESULT = subp fso.CreateFolder(RESULT) ENDIF FEND FUNCTION DeleteFolder(fso, path) RESULT = fso.DeleteFolder(path, TRUE) FEND FUNCTION Decompile(fso, chmFile, outPath=NULL) RESULT = outPath IF RESULT = NULL THEN RESULT = GetTempFolder(fso, TRUE) EXEC("hh.exe -decompile " + RESULT + " " + chmFile, TRUE) IFB fso.GetFolder(RESULT).Files.Count = 0 THEN IF outPath = NULL THEN DeleteFolder(fso, RESULT) RESULT = NULL ENDIF FEND FUNCTION GetKeywordsFromFile(fso, path) DIM i, j, k, l, ie, fid = -1, tar, n, r HASHTBL res TRY ie = CREATEOLEOBJ("InternetExplorer.Application") ie.Navigate("about:blank") fid = FOPEN(path) ie.Document.body.innerHTML = FGET(fid, F_ALLTEXT) FCLOSE(fid) fid = -1 FOR l = 0 TO ie.Document.body.childNodes.length - 1 IF ie.Document.body.childNodes.item(l).nodeName <> "UL" THEN CONTINUE tar = ie.Document.body.childNodes.item(l).childNodes FOR i = 0 TO tar.length - 1 n = tar.Item(i) IF n.nodeName <> "LI" THEN CONTINUE FOR j = 0 TO n.childNodes.length - 1 IF n.childNodes.item(j).nodeName <> "OBJECT" THEN CONTINUE n = n.childNodes.item(j) BREAK NEXT // 特殊文字系がサポートできないけど、ま、あきらめる r = SAFEARRAY(0, 1) k = 0 FOR j = 0 TO n.childNodes.length - 1 IF n.childNodes.item(j).nodeName <> "param" THEN CONTINUE r[k] = n.childNodes.item(j).value k = k + 1 IF k > 1 THEN BREAK NEXT res[LENGTH(res)] = r NEXT NEXT FINALLY ie.Quit() IF fid <> -1 THEN FCLOSE(fid) ENDTRY RESULT = SAFEARRAY(0, LENGTH(res) - 1) FOR i = 0 TO LENGTH(res) - 1 RESULT[i] = res[i] NEXT FEND FUNCTION UpdateKeywords(iniPath=NULL, chmPath=NULL, ext=".hhk") IF chmPath = NULL THEN chmPath = GET_UWSC_DIR + "\uwsc.chm" DIM fso = CREATEOLEOBJ("Scripting.FileSystemObject"), path = NULL, f = -1 IF iniPath = NULL THEN iniPath = ".\help.uws" DIM d = fso.GetFile(chmPath).DateLastModified, ds = READINI("ChmInfo", "LastModified", iniPath) IFB d = ds THEN RESULT = TRUE EXIT ENDIF TRY // UWSC.chmを展開 path = Decompile(fso, chmPath) // キーワードを読み込む DIM i, j, tmp HASHTBL res FOR i = 0 TO GETOLEITEM(fso.GetFolder(path).Files) - 1 tmp = ALL_OLE_ITEM[i].Path IFB COPY(tmp, LENGTH(tmp) - LENGTH(ext) + 1) = ext THEN tmp = GetKeywordsFromFile(fso, tmp) FOR j = 0 TO LENGTH(tmp) - 1 res[LENGTH(res)] = tmp[j] NEXT ENDIF NEXT // 一旦空にする f = FOPEN(iniPath, F_READ OR F_WRITE) j = FGET(f, F_LINECOUNT) i = 1 tmp = TRUE WHILE i <= j IFB tmp THEN IF POS("[Keywords]", FGET(f, i)) = 1 THEN tmp = FALSE i = i + 1 ELSE IFB POS("[", FGET(f, i)) = 1 THEN FPUT(f, "", i, F_INSERT) BREAK ELSE FDELLINE(f, i) j = j - 1 ENDIF ENDIF WEND FCLOSE(f) f = -1 _keywords = "[Keywords]<#CR>" RESULT = LENGTH(res) FOR i = 0 TO RESULT - 1 WRITEINI("Keywords", res[i][0], res[i][1], iniPath) _keywords = _keywords + res[i][0] + "=" + res[i][1] + "<#CR>" NEXT WRITEINI("ChmInfo", "LastModified", d, iniPath) _keywords = _keywords + "[EndIni]" FINALLY IF path <> NULL THEN DeleteFolder(fso, path) IF f <> -1 THEN FCLOSE(f) ENDTRY FEND FUNCTION Open(keyword=EMPTY, chmPath=NULL) IF chmPath = NULL THEN chmPath = GET_UWSC_DIR + "\uwsc.chm" IF _keywords = NULL THEN _keywords = _ini_area DIM url = EMPTY IFB LENGTH(keyword) THEN DIM regexp = CREATEOLEOBJ("VBScript.RegExp") regexp.Global = TRUE regexp.IgnoreCase = TRUE regexp.Multiline = TRUE regexp.Pattern = "[\s\S]*\n\[Keywords\]([\s\S]*?\n)\[[\s\S]*" DIM keywords = regexp.Replace(_keywords, "$1") regexp.Pattern = "^(" + keyword + "[^=\r\n]*)=([^#\r\n]*(?:#(.*))?)$" DIM ms = regexp.Execute(keywords), i HASHTBL urls FOR i = 0 TO ms.Count - 1 IFB urls[ms.Item(i).SubMatches.Item(1), HASH_EXISTS] THEN urls[ms.Item(i).SubMatches.Item(1)] = urls[ms.Item(i).SubMatches.Item(1)] + "/" + ms.Item(i).SubMatches.Item(0) ELSE urls[ms.Item(i).SubMatches.Item(1)] = ms.Item(i).SubMatches.Item(0) ENDIF NEXT url = " ::/" IFB LENGTH(urls) = 1 THEN url = url + urls[0, HASH_KEY] ELSEIF LENGTH(urls) THEN i = SLCTBOX(SLCT_NUM, 0, "開くキーワードを指定してください", urls) IF i >= 0 THEN url = url + urls[i, HASH_KEY] ENDIF ENDIF RESULT = (LENGTH(url) = 0) OR (LENGTH(url) > 4) IF RESULT THEN EXEC("hh.exe " + chmPath + url) FEND DIM _keywords = NULL TEXTBLOCK _ini_area [StartIni] [Keywords] [ChmInfo] [EndIni] ENDTEXTBLOCK ENDMODULE
解説
TEXTBLOCKにiniを持つ方式です。
[Keywords]セクションに、キーワードを持ちます。
[ChmInfo]セクションに、キーワードを抽出したchmファイルの情報(最終更新日時)を持ちます。
最終更新日時がこれと異なった場合、更新がかかることになります。
開くのは、Help.Open関数。他の関数は更新用です。
Help.UpdateKeywords関数でキーワードを更新する想定です。
Help.Open関数に組み込んで使っても良い気がしますが、、、一応独立させています。