2024年8月19日月曜日

PPvで前回開いたパスを開く ~まだ俺達はPPvの真の性能を引き出していない~

概要

PPxにおいて、ビューアであるPPvは何枚でも開くことができる。だが、僕は普段は、PPcと紐づけた形(連動ビュー)でしかPPvを使えていない。この場合、使えるPPvの数はPPcの数に規定されることになる。せいぜい3、4枚といったところだ。 これでは、PPvの真の性能を引き出しているとはいえないんじゃないか。PPvをズラッと何枚も並べ、それぞれに異なるファイルを表示して見比べる活用法があるんじゃないか。このような問題意識を、僕はずっと持っていた。

この問題には、過去にも何度か取り組んだことがあるが、あまり成果は出なかった。ここからは「ファイルパスはどこにどの形式で保存するか」「位置関係は保存すべきか」「保存したとしてどう再現するか」「保存したパスをどのIDのPPVで開くか」等の複雑な課題が生じてくる。これを解決しようとすると、スクリプトなり、リストファイルなりを駆使した、運用が複雑なものが出来上がる。そして結局は、その複雑さゆえに使わなくなる。これが今までのパターンだった。 最近、「PPv終了時にIDごとにパスを保存し、次回起動時にはそのパスを開く」という単純な仕組みで、これらの課題は解決するんじゃないか、と思いついた。

実装について

以下の形で実装する。

  • データの保存には、S_xxxを活用する。例えばPPV[F]のパスはS_ppvpath:Fに、PPV[G]のパスはS_ppvpath:Gに保存する、というように
  • PPV[F]~PPV[W]を今回の用途に使う。PPV[A]~PPV[E]は、通常のPPcと紐づけた運用に。PPV[X}~PPV[Z]は他の特殊な用途にとっておく

準備

以下を編集して取込。

KV_main    = {    ; PPvメイン窓
CLOSEEVENT    ,*ifmatch "o:e,a:d-",%FCD %: *setcust S_ppvpath:%*rightstr("%n", 1)=%FCD %: *stop
    *deletecust S_ppvpath:%*rightstr("%n", 1)
FIRSTEVENT    ,*ifmatch "/[a-ex-z]/",%*rightstr("%n", 1) %: *stop
    *ifmatch !0,0%*getcust(S_ppvpath:%*rightstr("%n", 1)) %: %J%*getcust(S_ppvpath:%*rightstr("%n", 1))
    *mapkey use,K_ppvv
}

K_ppvv    = {    ; 紐づけなしPPv
ESC    ,%J"no such file"
^N    ,*script %0Script\open_plural_ppv.js,2
O    ,*openppcv %FCD
}

K_ppcv    = {    ; 紐づけなしPPvから起動したPPc
ENTER    ,*ifmatch "o:e,a:d+",%FCD %: %K"@ENTER" %: *stop
    %Oi *windowsize %*extract(%%NV%*getcust(_User:syncidppcv)),%*windowrect(,w),%*calc("%*windowrect(,h)*2") %: *closeppx %n %: *stop
Q    ,%Oi *windowsize %*extract(%%NV%*getcust(_User:syncidppcv)),%*windowrect(,w),%*calc("%*windowrect(,h)*2") %: *closeppx %n
}

_Command    = {    ; ユーザコマンド・関数
openppcv    = *setcust _User:syncidppcv=%*rightstr("%n", 1)
    *windowsize %N,%*windowrect(,w),%*calc("%*windowrect(,h)/2")
    *ppc -bootid:%*getcust(_User:syncidppcv) -single -k %%j"%*arg(1)" %%: *mapkey use,K_ppcv %%: *ppvoption sync %*getcust(_User:syncidppcv) %%: *fitwindow %N,%%N,4 %%: *windowsize %%N,%*windowrect(,w),%*windowrect(,h)
}

以下をScriptフォルダにopen_plural_ppv.jsという名前で保存。今まで僕がつくってきたスクリプトとは違い、ES6で書いているので注意。

//!*script
// S_ppvpathに保存したパスをPPvで開く。S_ppvpath:FならPPV[F]で。S_ppvpath:GならPPV[G]で、というように
// 例:*script %0Script\open_plural_ppv.js,1
// 第一引数
// 0:パスを保持したPPvを一斉に起動
// 1:パスを保持したPPvを一斉に起動。一つもなければPPvを一つ開く
// 2:PPvを一つ開く
// 最初のPPVID
// A:65 Z:90
const PPV_ID_START=70;
// PPVIDの範囲
const PPV_MAX=18;
const fs = PPx.CreateObject("Scripting.FileSystemObject");
// 引数がなければ終了
if (PPx.Arguments.Length < 1){
PPx.SetPopLineMessage("引数が正しくありません。");
PPx.Quit(-1);
}
if (PPx.Arguments(0)==0){
openPluralPPv();
} else if (PPx.Arguments(0)==1){
openPluralPPv(1);
} else if (PPx.Arguments(0)==2) {
openNewPPv();
}
// 本体
function openPluralPPv(arg){
const id = [...Array(PPV_MAX)].map((v, i) => String.fromCodePoint(i + PPV_ID_START));
let count = 0;
id.forEach(v => {
const p = PPx.Extract("%*getcust\(S_ppvpath:"+v+"\)").replace(/^"(.*)"$/, '$1'); // 両端の""を取る
if (fs.FileExists(p)) {
PPx.Execute("*ppv -bootid:"+v+" \""+p+"\"");
count ++;
}
});
if (count==0 && arg==1) openPPv();
}
// S_ppvpathにパスが保存されていないPPVを一つ開く
function openPPv(){
const id = [...Array(PPV_MAX)].map((v, i) => String.fromCodePoint(i + PPV_ID_START));
id.some(v => {
const p = PPx.Extract("%*getcust\(S_ppvpath:"+v+"\)").replace(/^"(.*)"$/, '$1');
if (!fs.FileExists(p)) {
PPx.Execute("*ppv -bootid:"+v);
return true
}
});
}
// PPVを新たに一つ開く
function openNewPPv(){
const ppvlist=PPx.Extract("%*ppxlist()").split(",");
const id = [...Array(PPV_MAX)].map((v, i) => String.fromCodePoint(i + PPV_ID_START));
id.some(v => {
if (!ppvlist.includes(`V_${v}`)){
PPx.Execute("*ppv -bootid:"+v);
return true
}
});
}

やり方

以下のコマンドで、S_ppvpathにパスが保存してあるPPVを一斉に開く。一つもなければ、空の状態のPPvを一つ開く。

*script %0Script\open_plural_ppv.js,1

PPvを新たに一つ開きたい場合は、上のコマンドで開いたPPv上で[^N]を押すか、以下のコマンドを任意の場所で実行する。

*script %0Script\open_plural_ppv.js,2

表示ファイルを変えたい場合は、PPV上で[O]を押す。すると、PPCが表示され、PPvが連動ビューの状態になる。目的のファイルを見つけたら、[Enter]か[Q]を押す。 もちろん、単純にドラッグアンドドロップを使うのでもいい。

「もうこのファイルは次回は表示しなくていいや」という場合は、PPV上で[ESC]を押す。すると、存在しないファイルを表示する。この状態で閉じると、保存したパスがリセットされる。

活用案

  • 開きっぱなしにしておきたいテキストを表示する
  • todoを書いたテキストを表示する
  • 見てると落ち着く写真を表示する
  • 見比べたい資料を表示する

といった活用方法がありそう。

2024年8月12日月曜日

PPV単体で書庫内の画像を閲覧

書庫内の画像をPPvで閲覧できるようにする。漫画ビューアでよくあるやつです。 「PPcで書庫に潜ってPPvで連動ビューしたらいいだけじゃん」と言われたらたしかにそうなのだが、PPv単体でできたら便利かもしれないと思いました(小並感)。

準備

以下をgetarchivefiles.jsという名前でスクリプトフォルダに保存。

//!*script
// 書庫内のファイル名をS_xxx1 S_xxx2 S_xxx3 ... と連番で保存。「書庫のパス\S_xxx1の内容」を返す
// PPvを単体で画像ビューアのように扱うためのスクリプト
// 第一引数:書庫のパス
// 第二引数:ファイル名を保存するS_xxx
// 例: *ppv %*script(%0Script\getarchivefiles.js,%FCD,S_archivepages)
// 引数がなければ終了
if (PPx.Arguments.Length < 2){
PPx.SetPopLineMessage("引数が正しくありません。");
PPx.Quit(-1);
}
var source_file = PPx.Arguments(0);
var user_table = PPx.Arguments(1);
var filelist = PPx.Extract("%*run\(tar -tf \""+source_file+"\"\)").split("\r\n");
PPx.Execute("*deletecust \""+user_table+"\""); // S_xxxの初期化
var a = PPx.Extract("%*name\(DCN,"+source_file+"\)"); // 両端の""を取る
for(i = 0; i < filelist.length-1; i++) {
var filepath = PPx.Extract('%*name(KDC,'+a+"\\"+filelist[i]+')'); // パス区切りを「\」に統一
PPx.Execute("*setcust "+user_table+":"+i+"="+filepath);
};
PPx.Result=PPx.Extract("%*getcust\("+user_table+":0\)"); // 「書庫のパス\S_xxx1の内容」を返す

以下を編集して取込。

K_archiveview    = {
RIGHT    ,*ifmatch 0,0%si"pagenum" %: *string i,pagenum=0
    *string i,pagenum=%*calc("%si"pagenum"+1") %: *string o,name=%%*getcust(S_archivepages:%si"pagenum")
    *ifmatch !0,0%sgo"name" %: %J%sgo"name" %: *stop
    *string i,pagenum=%*calc("%si"pagenum"-1")
LEFT    ,*ifmatch 0,0%si"pagenum" %: *string i,pagenum=0 %: *stop
    *if %*calc(%si"pagenum") == 0 %: *stop
    *string i,pagenum=%*calc("%si"pagenum"-1") %: *string o,name=%%*getcust(S_archivepages:%si"pagenum") %: %J%sgo"name"
}

%si"pagenum"は現在見ているページ番号。左右カーソルで1ずつ増減する。

やり方

PPcで書庫ファイルにカーソルをあわせ、以下のコマンドを実行。

*ppv %*script(%0Script\getarchivefiles.js,%FCD,S_archivepages) -k *mapkey use,K_archiveview

最初の画像が表示される。カーソル左右で表示ファイルを切り替える。