説明

リストファイルのコメント欄にタグを書き込んで運用するシステム。
本格的なタグ管理はできませんが手軽に使えます。次のような機能を持ちます。

  • 複数のエントリに対するタグの追加・削除。
  • 複数のタグリストの切り替え。
  • commentSearch.jsを使って&-or検索で絞り込める。
  • リストファイル外でも使える。
  • タグに色付けしてPPvで表示。(おまけ機能)
  • スクリプト内でcompCode.jsを使用。
  • スクリプト内おまけ機能でWindowModuleを使用。

タグ用メニューの説明

項目 内容
1:TagSys 一行編集が起動してタグリストを選択できます。
通常、一行編集には%'list'%\tag\が挿入されますが、カレントディレクトリに01_TAG.TXTがあればそちらを挿入します。選択したパスが存在しないときは_default.txtを読み込みます。
リスト選択後にメニュー下部にタグ項目が追加されます。
A:add 一行編集で選択したタグをエントリに追加します。
スペース区切りで複数のタグを追加できます。
R:remove 一行編集で選択したタグをエントリから削除します。
スペース区切りで複数のタグを削除できます。
E:edit taglist 現在選択中のタグリストを編集します。保存と同時にメニューを再生成します。
V:tag view (おまけ機能)
カーソル移動するとPPv[T]に色付けされたタグが表示されます。再実行で解除。
※カーソル移動ごとにファイルを読み書きしているので連続移動するとエラーがでます。
*entrytipに組み込むのがいいかもしれません。
  • 1:TagSysからタグリストを選択すると_User:taglistにパスが設定されます。
  • タグ項目の生成では一つのタグにつき、二つの項目が追加されます。-が付いた項目は削除用です。
  • 重複するタグは一つにまとめられます。

使い方

  1. tagMakeMenu.jsの初期設定をする。
  2. *edit -new -lf -utf8bom %'list%\tag\_default.txt(初期値。スクリプト内変数TAG_LISTと同一のパス)を実行してタグリストを生成する。(必須)
  3. 2.のファイルに使いたいタグを書き込む。タグは一行で1タグと認識される。
  4. 次にタグ用のメニューを呼び出し、1:TagSysを押すと一行編集が起動するので_default.txtを選択するとメニューにタグが追加される。
  5. 適当にエントリにタグを付けていく。
  6. コメントサーチで絞り込む。

タグリスト作成とメニュー生成までの手順.gif
タグ付けとタグの絞り込み.gif

タグの書式

タグ ;アルファベット一文字 ;数字
最初のコメントはメニューのショートカットキー、二つ目のコメントはansi色番号を指定できる。

  • あとで読む ;a これはメニューにA: あとで読むとして登録される。
  • いますぐ読め! ;いま! これはメニューには登録されない。
  • 緑 ; ;32 V:tag viewでPPvに表示されるタグが[]のように色づけされる。

ansi色番号はansi colorなどでWeb検索して調べて下さい。

キーバインド

KEY COMMAND
[ コメント
CTRL+[ コメントサーチ
CTRL+S(一行編集) 編集中のタグを保存。

設定

A_exec = {
scr  =    ;スクリプトをまとめておくディレクトリパス
cfg  =    ;PPxの設定ファイルをまとめておくディレクトリパス
list =    ;読み書きするリストをまとめておくディレクトリパス
}

; キーに割り当てる
-|M_Ueco =
M_Ueco = {
&1:TagSys = *string o,basepath=%'list'%\tag\
            *ifmatch "o:e,a:d-",01_TAG.TXT %: *string o,basepath=01_TAG.TXT
            *string o,listpath=%*input("%so'basepath'" -title:"Select Taglist.." -k *completelist)
            *script %'scr'%\tagMakeMenu.js,%so"listpath"
-- =
ex = ??M_UecoSub
}

KC_main = {
'['   , *string o,cmnt=%*comment
        *ifmatch *"*,0%so"cmnt" %: *string o,cmnt=%*regexp(%so"cmnt","/""/""""""""/g")
        *comment extract,"%*input("%so'cmnt'" -title:"Comment.." -mode:Re -k *mapkey use,K_tagSysMap)"
^'['  , *script %'scr'%\commentSearch.js,filter
}

KV_img = {
'[' , *string o,cmnt=%*extract(C"%%*comment")
      *ifmatch *"*,0%so"cmnt" %: *string o,cmnt=%*regexp(%so"cmnt","/""/""""""""/g")
      *ifmatch !0,0%su"taglist" %: *string o,comp=*string e,filename=%su"taglist" %%: *completelist -set -file:%su"taglist" -detail:"user1" %%:
      *string o,cmnt=%*input("%so"cmnt"" -title:"Comment.." -mode:Re -k %so"comp" *mapkey use,K_tagSysMap)
      *execute C,*comment extract,"%so"cmnt"
}

-|K_tagSysMap =
K_tagSysMap = {
^S  , *script %'scr'%\appendText-utf8lf.js
      *linemessage save tag
      *script %'scr'%\tagMakeMenu.js
}



スクリプトの説明

  • appendText-utf8lf.js 一行編集からタグリストにタグを保存するときに使う。
  • tagColor.js _User:taglistを元に色付きタグファイル%'temp'%\ppxtags.tmpを生成する。
  • tagMakeMenu.js _User:taglistを設定。それを元にタグ用メニューzzUecoTagSys.cfgを生成し読み込む。
  • tagOperate.js エントリにタグを追加・削除する。
//!*script
/**
* utf8-lfで保存ファイルに追記
*/
PPx.Execute('*editmode -lf -codepage:65001 %: *replace %*edittext');
var text = PPx.Extract('%*edittext');
var filename = PPx.Extract('%se"filename"');
var st = PPx.CreateObject('ADODB.stream');
st.Open;
st.Type = 2;
st.Charset = 'UTF-8';
st.LoadFromFile(filename);
var textline = st.ReadText(-1).split('\u000A');
var omitByte = -1;
for (var i = textline.length; i-- ;) {
if (textline[i] !== '') {
if (textline.length - 1 === i) {
omitByte = 0;
text = '\u000A' + text;
}
break;
}
omitByte = omitByte + 1;
}
// 結果を書き出してメニューを上書き
st.Position = st.Size - omitByte;
st.SetEOS;
st.WriteText(text, 1);
st.SaveToFile(filename, 2);
st.Close;
//!*script
/**
* utf8-lfで保存ファイルに追記
*/
'use strict';
PPx.Execute('*editmode -lf -codepage:65001 %: *replace %*edittext');
let text = PPx.Extract('%*edittext');
const filename = PPx.Extract('%se"filename"');
const st = PPx.CreateObject('ADODB.stream');
st.Open;
st.Type = 2;
st.Charset = 'UTF-8';
st.LoadFromFile(filename);
const textline = st.ReadText(-1).split('\u000A');
let omitByte = -1;
for (let i = textline.length; i-- ;) {
if (textline[i] !== '') {
if (textline.length - 1 === i) {
omitByte = 0;
text = `\u000A${text}`;
}
break;
}
omitByte = omitByte + 1;
}
// 結果を書き出してメニューを上書き
st.Position = st.Size - omitByte;
st.SetEOS;
st.WriteText(text, 1);
st.SaveToFile(filename, 2);
st.Close;
//!*script
/**
* タグに色づけしてTEMP_FILEに出力
*/
var TEMP_FILE = PPx.Extract("%'temp'%\\ppxtags.tmp");
var st = PPx.CreateObject('ADODB.stream');
var g_tags = (function () {
// タグリスト読み込み
var tags = [];
st.Open;
st.Type = 2;
st.Charset = 'UTF-8';
st.LoadFromFile(PPx.Extract('%su"taglist"'));
tags = st.ReadText(-2).split('\u000A');
st.Close;
return tags;
})();
var g_comments = PPx.Entry.comment.split(' ');
var result = [];
for (var i = 0, l = g_comments.length; i < l; i++) {
var thisTag = g_comments[i];
for (var j = g_tags.length; j--;) {
var v = (function (data) {
var data_ = data.split(' ;');
return {
tag: data_[0],
color: data_[2]
}
})(g_tags[j]);
if (~thisTag.indexOf(v.tag) && v.color !== undefined) {
thisTag = '[' + v.color + 'm' + v.tag + '';
}
}
result.push(thisTag);
}
// 結果を書き出して上書き
st.Open;
st.Type = 2;
st.Charset = 'UTF-8';
st.Position = 0;
st.WriteText(result.join(' '));
st.SaveToFile(TEMP_FILE, 2);
st.Close;
PPx.Result = TEMP_FILE;
view raw tagColorize.js hosted with ❤ by GitHub
//!*script
/**
* タグに色づけしてTEMP_FILEに出力
*/
'use strict';
const TEMP_FILE = PPx.Extract("%'temp'%\\ppxtags.tmp");
const st = PPx.CreateObject('ADODB.stream');
const g_tags = (() => {
// タグリスト読み込み
let tags = [];
st.Open;
st.Type = 2;
st.Charset = 'UTF-8';
st.LoadFromFile(PPx.Extract('%su"taglist"'));
tags = st.ReadText(-2).split('\u000A');
st.Close;
return tags.map(v => v.split(' ;'));
})();
const g_comments = PPx.Entry.comment.split(' ');
let result = [];
for (let i = g_comments.length; i--;) {
let thisTag = g_comments[i];
for (let [tag, ,color] of g_tags.values()) {
if (~thisTag.indexOf(tag) && color !== undefined) {
thisTag = `[${color}m${tag}`;
}
}
result.push(thisTag);
}
// 結果を書き出して上書き
st.Open;
st.Type = 2;
st.Charset = 'UTF-8';
st.Position = 0;
st.WriteText(result.join(' '));
st.SaveToFile(TEMP_FILE, 2);
st.Close;
PPx.Result = TEMP_FILE;
//!*script
/**
* タグリストからメニューを生成
*
* PPx.Arguments(
* 0: tag-list filepath
* )
*/
/////////* 初期設定 *////////////
// 項目数のカウントごとにメニューに縦区切りを入れる
var sep_count = 12;
// タグシステムメニュー項目名
var MENU_TITLE = 'M_UecoSub';
// タグシステム用キーバインド
var KEY_BIND = 'K_tagSysMap';
// 標準のタグリスト
var TAG_LIST = "%'list'%\\tag\\_default.txt";
// タグリストから生成されるタグシステムメニュー
var MENU_CFG = "%'cfg'%\\zzUecoTagSys.cfg";
/////////////////////////////////
var listPath = (function () {
var fso = PPx.CreateObject('Scripting.FileSystemObject');
var path;
if (PPx.Arguments.length !== 0) {
path = PPx.Extract('%*name(DC,' + PPx.Arguments(0) + ')');
}
return fso.FileExists(path) ? path : TAG_LIST;
})();
// タグリスト読み込み
var st = PPx.CreateObject('ADODB.stream');
st.Open;
st.Type = 2;
st.Charset = 'UTF-8';
st.LoadFromFile(PPx.Extract(listPath));
var tags = st.ReadText(-1).split('\u000A');
st.Close;
// タグメニュー作成
var compTag = function (title) {
return '%*script(%\'scr\'%\\compCode.js,"i","""%%","' + title * '","*string e,filename=%%%%su""taglist"" %%%%: *completelist -file:' + listPath + ' -detail:""user1"" %%%%: *mapkey use,' + KEY_BIND + '")';
};
var g_Xwin = PPx.Extract('%*getcust(X_win:v)');
var g_header = [
'-|' + MENU_TITLE + ' =',
MENU_TITLE + ' = {',
'&T:add = *script %\'scr\'%\\tagOperate.js,push,"' + compTag('add Tag..') + '"',
'&R:remove = *script %\'scr\'%\\tagOperate.js,remove,"' + compTag('remove Tag..') + '"',
'&E:edit taglist = *edit -lf -utf8bom %su"taglist" %: *script %\'scr\'%\\tagMakeMenu.js,%su"taglist"',
// この要素はPPvの表示設定。好みに合わせて変更。
'&V:tag view = *if 0%NVT %: *linecust tagView,KC_main:SELECTEVENT, %: *closeppx VT %: *setcust X_win:v=' + g_Xwin + ' %: *stop\u000A' +
'\u0009*string p,vState=1\u000A' +
'\u0009*setcust X_win:v=B100100100\u000A' +
'\u0009%Oi *ppv -r -bootid:t -k %(*execute C,*fitwindow %%N-R,%%NVT,0 %%: *topmostwindow %%NVT,1 %%: *wait 100,2 %%: *focus%)\u000A' +
'\u0009*linecust tagView,KC_main:SELECTEVENT,%(%Oa *ppv -r -bootid:t %*script(%\'scr\'%\\tagColorize.js) -k *focus%)\u000A' +
'\u0009%K"@LOADCUST',
'-- ='
];
var g_footer = '}';
var g_items = (function () {
var items = [];
for (var i = 0, l = tags.length; i < l; i++) {
var tag = tags[i];
if (tag === '') {
continue;
}
var tag_ = tag.split(';');
if (tag_[1] === undefined || !/[a-zA-Z]/.test(tag_[1])) {
continue;
}
var item = {
key: tag_[1].substring(0, 1).toUpperCase(),
name: tag_[0].replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '')
};
items.push(
'&' + item.key + ': ' + item.name + ' = *script %\'scr\'%\\tagOperate.js,push,"' + item.name + '"\u000A' +
'&' + item.key + ': -' + item.name + ' = *script %\'scr\'%\\tagOperate.js,remove,"' + item.name + '"'
);
}
items.sort();
return g_header.concat(items);
})();
// 縦区切り挿入
while (g_items.length > sep_count) {
g_items.splice(sep_count, 0, '|| =');
sep_count = sep_count * 2;
}
// 結果を書き出してメニューを上書き
st.open;
st.Position = 0;
st.WriteText(g_items.concat(g_footer).join('\u000A'));
st.SaveToFile(PPx.Extract(MENU_CFG), 2);
st.Close;
// メニューをPPxに反映
PPx.Execute(
'*setcust _User:taglist=' + listPath + ' %:' +
'*setcust @' + MENU_CFG
);
view raw tagMakeMenu.js hosted with ❤ by GitHub
//!*script
/**
* タグリストからメニューを生成
*
* PPx.Arguments(
* 0: tag-list filepath
* )
*/
'use strict';
/////////* 初期設定 *////////////
// 項目数のカウントごとにメニューに縦区切りを入れる
let sep_count = 12;
// タグシステムメニュー項目名
const MENU_TITLE = 'M_UecoSub';
// タグシステム用キーバインド
const KEY_BIND = 'K_tagSysMap';
// 標準のタグリスト
const TAG_LIST = "%'list'%\\tag\\_default.txt";
// タグリストから生成されるタグシステムメニュー
const MENU_CFG = "%'cfg'%\\zzUecoTagSys.cfg";
/////////////////////////////////
const listPath = (function () {
const fso = PPx.CreateObject('Scripting.FileSystemObject');
let path;
if (PPx.Arguments.length !== 0) {
path = PPx.Extract(`%*name(DC,${PPx.Arguments(0)})`);
}
return fso.FileExists(path) ? path : TAG_LIST;
})();
// タグリスト読み込み
const st = PPx.CreateObject('ADODB.stream');
st.Open;
st.Type = 2;
st.Charset = 'UTF-8';
st.LoadFromFile(PPx.Extract(listPath));
const tags = st.ReadText(-1).split('\u000A');
st.Close;
// タグメニュー作成
const compTag = title => (
`%*script(%'scr'%\\compCode.js,"i","""%%","${title}","*string e,filename=%%%%su""taglist"" %%%%: *completelist -file:${listPath} -detail:""user1"" %%%%: *mapkey use,${KEY_BIND}")`
);
const g_Xwin = PPx.Extract('%*getcust(X_win:v)') || 'B000000000' ;
const g_header = [
`-|${MENU_TITLE} =`,
`${MENU_TITLE} = {`,
`&T:add = *script %'scr'%\\tagOperate.js,push,"${compTag('add Tag..')}"`,
`&R:remove = *script %'scr'%\\tagOperate.js,remove,"${compTag('remove Tag..')}"`,
'&E:edit taglist = *edit -lf -utf8bom %su"taglist" %: *script %\'scr\'%\\tagMakeMenu.js,%su"taglist"',
// この要素はPPvの表示設定。好みに合わせて変更。
`&V:tag view = *if 0%NVT %: *linecust tagView,KC_main:SELECTEVENT, %: *closeppx VT %: *setcust X_win:v=${g_Xwin} %: *stop
*string p,vState=1
*setcust X_win:v=B100100100
%Oi *ppv -r -bootid:t -k %(*execute C,*fitwindow %%N-R,%%NVT,0 %%: *topmostwindow %%NVT,1 %%: *focus%)
*linecust tagView,KC_main:SELECTEVENT,%(%Oa *ppv -r -bootid:t %*script(%'scr'%\\tagColorize.js)%)
%K"@LOADCUST`,
'-- ='
];
const g_footer = '}';
const g_items = (() => {
let items = [];
for (const tag of tags) {
if (tag === '') {
continue;
}
const tag_ = tag.split(';');
if (tag_[1] === undefined || !/[a-zA-Z]/.test(tag_[1])) {
continue;
}
const item = {
key: tag_[1].substring(0, 1).toUpperCase(),
name: tag_[0].trim()
};
items.push(
`&${item.key}: ${item.name} = *script %'scr'%\\tagOperate.js,push,"${item.name}"\u000A` +
`&${item.key}: -${item.name} = *script %'scr'%\\tagOperate.js,remove,"${item.name}"`
);
}
items.sort();
return [...g_header, ...items];
})();
// 縦区切り挿入
while (g_items.length > sep_count) {
g_items.splice(sep_count, 0, '|| =');
sep_count = sep_count * 2;
}
// 結果を書き出してメニューを上書き
st.open;
st.Position = 0;
st.WriteText([...g_items, ...g_footer].join('\u000A'));
st.SaveToFile(PPx.Extract(MENU_CFG), 2);
st.Close;
// メニューをPPxに反映
PPx.Execute(
`*setcust _User:taglist=${listPath} %:` +
`*setcust @${MENU_CFG}`
);
//!*script
/**
* コメントにタグを付けたり外したり
*
* PPx.Arguments(
* 0: push | remove
* 1: tags
* )
*/
var g_args = (function () {
if (PPx.Arguments.length === 0) {
PPx.Echo('引数が足りません');
PPx.Quit(-1);
}
return {
order: PPx.Arguments(0),
tags: PPx.Arguments(1).split(' ')
};
})();
var cmd = {};
cmd['push'] = function (cmnts) {
var cmnts1 = (cmnts.length === 0) ? g_args.tags : cmnts.split(' ').concat(g_args.tags);
var exist = {};
var newCmnts = [];
for (var i = 0, l = cmnts1.length; i < l; i++) {
var thisComment = cmnts1[i];
if (!exist[thisComment]) {
exist[thisComment] = true;
newCmnts.push(thisComment);
}
}
return newCmnts.sort(function (a, b) {
return (a.toLowerCase() < b.toLowerCase()) ? -1 : 1;
});
};
cmd['remove'] = function (cmnts) {
var cmnts2 = cmnts.split(' ');
var i, l;
// 編集結果(削除するタグ)の重複チェック
// var exist = {};
// var rmTags = [];
// for (i = 0, l = g_args.tags.length; i < l; i++) {
// var thisComment = g_args.tags[i];
// if (!exist[thisComment]) {
// exist[thisComment] = true;
// rmTags.push(thisComment);
// }
// };
for (i = 0, l = g_args.tags.length; i < l;i++) {
var tag = g_args.tags[i];
for (var j = 0, k = cmnts2.length; j < k; j++) {
if (cmnts2[j] === tag) {
cmnts2.splice(j, 1);
}
}
}
return cmnts2;
};
var thisEntry = PPx.Entry;
thisEntry.FirstMark;
do {
var thisComment = (function () { return cmd[g_args.order](thisEntry.comment); })();
thisEntry.comment = thisComment.join(' ');
} while (thisEntry.NextMark);
PPx.Execute('*color back');
view raw tagOperate.js hosted with ❤ by GitHub
//!*script
/**
* コメントにタグを付けたり外したり
*
* PPx.Arguments(
* 0: push | remove
* 1: tags
* )
*/
'use strict';
const g_args = (() => {
if (PPx.Arguments.length === 0) {
PPx.Echo('引数が足りません');
PPx.Quit(-1);
}
return {
order: PPx.Arguments(0),
tags: PPx.Arguments(1).split(' ')
};
})();
const cmd = {};
cmd['push'] = (cmnts) => {
let cmnts1 = (cmnts.length === 0) ? g_args.tags : [...cmnts.split(' '), ...g_args.tags];
cmnts1 = Array.from(new Set([...cmnts1]));
return cmnts1.sort((a, b) => (a.toLowerCase() < b.toLowerCase()) ? -1 : 1);
};
cmd['remove'] = (cmnts) => {
let cmnts2 = cmnts.split(' ');
const rmTags = Array.from(new Set([...g_args.tags]));
for (const tag of rmTags.values()) {
cmnts2 = cmnts2.filter(v => v !== tag);
}
return cmnts2;
};
const thisEntry = PPx.Entry;
thisEntry.FirstMark;
do {
const thisComment = (() => cmd[g_args.order](thisEntry.comment))();
thisEntry.comment = thisComment.join(' ');
} while (thisEntry.NextMark);
PPx.Execute('*color back');