Skip to content

Instantly share code, notes, and snippets.

@u27a4
Last active November 20, 2018 16:10
Show Gist options
  • Save u27a4/e2097564770ee4ed7d16954d6c2ee132 to your computer and use it in GitHub Desktop.
Save u27a4/e2097564770ee4ed7d16954d6c2ee132 to your computer and use it in GitHub Desktop.
ファイルツリー for WZ Editor (https://www.wzsoft.jp/)
/**
* .概要
* WZ Editor にファイルツリーを追加するマクロ
*
* .使い方
* フォルダをエディタにドラッグ&ドロップすると、ツールウィンドウにファイル一覧が表示されます。
* ファイル一覧は右クリックメニューの設定から、ワイルドカードを使用してある程度カスタマイズできます。
*
* .導入方法
* このファイルをエディタ(管理者モード)で開き「メニュー > マクロ > プログラムの登録」を実行します。
* プラグインはエディタ再起動後から有効化されます。
*
* .動作環境
* WZ Editor 9 / 10
*
* filetree.c
* Copyright (c) 2018 u27a4
* MIT License
* http://opensource.org/licenses/mit-license.php
**/
#include <windows.h>
#include <text.h>
// プラグインの情報
author: u27a4
name: filetree
title: ファイルツリー
// 設定ダイアログの定義
pretext {
.フォルダ設定
FOLDER フォルダ(&F) str;histid=FOLDER;lcx=40;fit
MASK マスク(&K) str;histid=MASK;fit
DEMASK 除外マスク(&H) str;histid=DEMASK;fit
.表示設定
FICON ファイルアイコン(&A) str;str=📄;histid=FICON;fit
DICON フォルダアイコン(&B) str;str=📁;histid=DICON;fit
} prefs_dialog;
// 右クリックメニューの定義
pretext {
OK エディタで開く(&E)
NEWWND 新しいウィンドウで開く(&N)
EXPLOR エクスプローラで開く(&O)
RELOAD 更新(&R)
PREFS 設定(&S)
} popup_menu_items;
// ショートカットキーの定義
pretext {
{Enter} OK
{F5} RELOAD
} shortcut_keys;
// ID_FLTREE: ツールウィンドウのId
// ID_FLTRCG: ツールコンフィグのId
static void OpenFileTree();
// ファイル一覧を生成する
static void GetFiles(HTEXT filepaths, HTEXT filenames, HTEXT dir, CLM filter, CLM ignore, int depth, CLM dicon, CLM ficon)
{
WIN32_FIND_DATA fd;
HTEXT curFilePaths = newtext();
HTEXT curFileNames = newtext();
// 指定ディレクトリ内のすべてのファイルを列挙していく
HANDLE h = filefindfirst(textprintf("%s\\*", dir), &fd);
if (h != INVALID_HANDLE_VALUE)
{
do
{
if (ffdisdotdir(&fd) != FALSE // カレントor親ディレクトリの除外
|| fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN // 隠しファイルを除外
|| fd.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) // システムファイルを除外
{
continue;
}
HTEXT filename = textprintf("%ws", fd.cFileName);
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
for (int i = 0; i <= depth; i++)
{
add(filenames, ".");
}
addf(filenames, "%cs %s\n", dicon, filename);
addf(filepaths, "%s\\%s\n", dir, filename);
// ディレクトリを再帰的に探索する
GetFiles(filepaths, filenames, textprintf("%s\\%s", dir, filename), filter, ignore, depth + 1, dicon, ficon);
}
else if (!filter || pathmasksmatch(filename, filter) // 検索パターンに一致するファイルを追加
&& (!ignore || !pathmasksmatch(filename, ignore))) // 除外パターンに一致するファイルを除外
{
for (int i = 0; i <= depth; i++)
{
add(curFileNames, ".");
}
addf(curFileNames, "%cs %s\n", ficon, filename);
addf(curFilePaths, "%s\\%s\n", dir, filename);
}
} while (filefindnext(h, &fd));
addwhole(filenames, curFileNames);
addwhole(filepaths, curFilePaths);
filefindclose(h);
}
}
// 設定ダイアログを開く
static BOOL OpenPrefsDialog()
{
BOOL result;
HTEXT cfg = cfgnew(ID_FLTRCG);
HTEXT args = newtext();
args.cur = ID_FOLDER;
if (result = property(cfg, "ファイルツリー", dupstr(prefs_dialog), args))
{
idsetclm(cfg, ID_FILTER, cfg.clmfilter);
idsetclm(cfg, ID_IGNORE, cfg.clmignore);
idsetclm(cfg, ID_FOLDER, cfg.clmfolder);
}
return result;
}
// ビューフックプロシージャ
static BOOL ViewHookProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, HTEXT source)
{
switch(message)
{
case TWM_EVENT:
switch (wParam)
{
// ファイルがダブルクリックされたらエディタで開く
case ID_MUSDKL:
jumppara(source.textpaths, getcurpara(source.textnames));
if (fileisdir(source.textpaths) == FALSE)
{
return PostMessage(hWnd, TWM_EVENT, ID_CMDNT, ID_OK);
}
break;
// フォルダドロップされたら一覧を更新
case ID_DROP:
if (fileisdir((LPVOID)lParam))
{
HTEXT cfg = cfgnew(ID_FLTRCG);
idsetclm(cfg, ID_FOLDER, (LPVOID)lParam);
OpenFileTree();
return TRUE;
}
break;
}
break;
case TWM_COMMAND:
// メニュー選択時の処理
if (wParam == ID_CMENU)
{
int cmd = selectmenu(dup(popup_menu_items));
if (cmd)
{
PostMessage(hWnd, TWM_EVENT, ID_CMDNT, cmd);
}
return TRUE;
}
break;
}
return FALSE;
}
// ツールフックプロシージャ
static BOOL ToolWindowHookProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, HTEXT source)
{
HTEXT cfg;
switch (message)
{
case TWM_NOTIFYCMD:
switch (wParam)
{
case ID_OK:
case ID_NEWWND:
case ID_EXPLOR:
case ID_RELOAD:
case ID_PREFS:
return PostMessage(hWnd, TWM_COMMAND, wParam, 0);
}
break;
case TWM_COMMAND:
// 選択項目を取得できるようにしておく
jumppara(source.textpaths, getcurpara(source.textnames));
switch (wParam) {
case ID_OPEN:
case ID_OK:
// 選択項目がファイルなら絞り込みを解除してエディタで開く
if (fileisdir(source.textpaths) == FALSE)
{
source.textnames.v.clmfilter = NULL;
openfileeditor(source.textpaths, "-fhist(0) ");
}
break;
case ID_NEWWND:
// 選択項目がファイルなら絞り込みを解除してエディタで開く (SDI)
if (fileisdir(source.textpaths) == FALSE)
{
source.textnames.v.clmfilter = NULL;
openfileeditor(source.textpaths, "-fhist(0) -sdi");
}
break;
case ID_EXPLOR:
// 選択項目がファイルなら親ディレクトリをエクスプローラで開く
if (fileisdir(source.textpaths) == FALSE)
{
HTEXT dir = dupstr(source.textpaths);
pathsetparent(dir);
shellopen(dir);
}
else
{
shellopen(source.textpaths);
}
break;
case ID_PREFS:
// 設定を開く
if (OpenPrefsDialog())
{
PostMessage(hWnd, TWM_COMMAND, ID_RELOAD, 0);
}
break;
case ID_RELOAD:
// 最新の情報に更新
cfg = cfgnew(ID_FLTRCG);
if (fileisdir(cfg.clmfolder))
{
HTEXT dir = dupclm(cfg.clmfolder);
pathsetdir(dir, FALSE);
delall(source.textnames);
delall(source.textpaths);
addf(source.textnames, ".%cs %s\n", cfg.clmdicon, pathgetfile(dir));
addf(source.textpaths, "%s\n", dir);
GetFiles(source.textpaths, source.textnames, dir, cfg.clmfilter, cfg.clmignore, 1, cfg.clmdicon, cfg.clmficon);
jumptop(source.textnames);
jumptop(source.textpaths);
vcmdexec(source.textnames.v, ID_OLFL1); // 先頭ノードを開く
}
break;
case ID_CLOSE:
case ID_CANCEL:
PostMessage(hWnd, WM_CLOSE, 0, 0);
break;
}
break;
case WM_TIMER:
if (wParam == 101) {
// テキストの参照管理(?)
HTEXT text = getfocus();
if (text && text != source.text)
{
if (text.v.mode == 0 || text.v.mode == ID_EDITOR)
{
delete(source.text);
source.text = NULL;
source.text = refer(text);
}
}
}
break;
case WM_DESTROY:
// テキスト削除
delete(source.textpaths);
delete(source.textnames);
delete(source.text);
delete(source);
break;
}
return FALSE;
}
// エディタのフックプロシージャ
BOOL EditorHookProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, HTEXT source)
{
switch (message)
{
case TWM_EVENT:
switch (wParam)
{
case ID_DROP:
if (fileisdir((LPVOID)lParam))
{
HTEXT cfg = cfgnew(ID_FLTRCG);
idsetclm(cfg, ID_FOLDER, (LPVOID)lParam);
OpenFileTree();
return TRUE;
}
break;
}
break;
}
return FALSE;
}
// ファイルツリーウィンドウを生成する
static HWND CreateFileTree()
{
HTEXT cfg = cfgnew(ID_FLTRCG);
// 引数のファイルパス末尾に '\' があれば除去
HTEXT filepath = dupclm(cfg.clmfolder);
pathsetdir(filepath, FALSE);
// ツールウィンドウの生成とプロパティの設定
HWND hWnd = wtoolnew(ID_FLTREE);
hWnd.clmtitle = "ファイル";
hWnd.sbhorz = TRUE;
// ツリービューで使用するテキストの生成
HTEXT source = refer(newtext());
source.text = refer(getfocus());
source.textnames = newtext();
source.textpaths = newtext();
// ツリービューの生成とショートカットの登録
HWND hDialog = dialogpanenew(hWnd);
HVIEW view = vnew(source.textnames, hDialog, WS_VISIBLE | WS_TABSTOP | TWS_OLT | TWS_BORDER | WS_HSCROLL | WS_VSCROLL, WID1, 0);
jumptop(view.textkey);
add(view.textkey, shortcut_keys);
// フックプロシージャの登録
vsethook(view, (WHOOKPROC)ViewHookProc, source);
wsethook(hWnd, (LPVOID)ToolWindowHookProc, source);
// 「標準」の色設定を反映
HTEXT text = newtext();
if (load(text,"wzcfg://idview.cfg"))
{
msgjumpbody(text);
HTEXT msg = walkmsgs(text);
do
{
if (!clmcmp(mhgetclm(msg, ID_TITLE), "標準"))
{
HTEXT props = vpropget(view);
props.coltxt = msg.coltxt;
props.colbak = msg.colbak;
props.colsel = msg.colsel;
props.colbks = msg.colbks;
view.flush();
break;
}
} while (!(msg = walkmsgs(text)));
}
// ファイル一覧を更新
PostMessage(hWnd, TWM_COMMAND, ID_RELOAD, 0);
// 参照管理用のタイマー起動
SetTimer(hWnd, 101, 100, 0);
return hWnd;
}
// ファイルツリーを開く
static void OpenFileTree()
{
HWND hWnd = wtoolfind(ID_FLTREE);
if (hWnd)
{
// 既存ウィンドウをポップアップしてリロード
hWnd.popup();
PostMessage(hWnd, TWM_COMMAND, ID_RELOAD, 0);
}
else
{
dialogopen(CreateFileTree());
}
}
// プラグインがロードされたときに実行される
int plugin_editor(HWND hWnd)
{
if (!wishook(hWnd, (LPVOID)EditorHookProc))
{
waddhook(hWnd, (LPVOID)EditorHookProc, NULL);
}
return 0;
}
filetree {
title: 「ファイルツリー」ツールをツールビューに表示します。
tool: filetree
if (OpenPrefsDialog())
{
OpenFileTree();
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment