Obsidian Templater Active Task v2 250904
作成日: 2025年9月4日
code:js
<%*
/**
* 実行中タスク末尾へカーソル移動(Templater直書き)
* 優先順:
* 1) 実行中タスク(未チェックかつ単独 hh:mm。@hh:mm や hh:mm-hh:mm は除外)
* 2) 未実行タスク(未チェックかつ @以外の時刻表記なし。@hh:mm はあってよい)
* 3) 完了タスク(hh:mm-hh:mm を含む)…末尾から
* 見つかった行の「行末」にカーソルを移動
*/
const content = tp.file.content ?? "";
const lines = content.split("\n");
// ===== エディタ取得(tp.editor が無い環境でも動くように) =====
let editor = tp?.editor;
if (!editor || typeof editor.setCursor !== "function") {
const activeEditor = app?.workspace?.activeEditor;
if (activeEditor?.editor && typeof activeEditor.editor.setCursor === "function") {
editor = activeEditor.editor;
}
}
if (!editor) {
// 実行時にエディタが無い(読み取り専用ペインやモーダル等)場合の保険
if (typeof Notice !== "undefined") new Notice("アクティブなエディタが見つかりません。エディタ上で実行してください。");
return;
}
// ===== 判定用正規表現 =====
const reUnchecked = /^\s*-\s\\s\/; // 未チェック
const reRange = /\b(?:01\d|20-3):0-5\d-(?:01\d|20-3):0-5\d\b/; // hh:mm-hh:mm
const reAtTime = /@(?:01\d|20-3):0-5\d\b/; // @hh:mm(今回は除外/許容判定用に使うだけ)
const rePlainTime = /(^|^@)\b(?:01\d|20-3):0-5\d\b/; // 先頭が@でない hh:mm を含む
// ===== 判定関数 =====
const isRunning = (line) =>
reUnchecked.test(line) && // 未チェック
rePlainTime.test(line) && // 単独 hh:mm(@でない)
!reRange.test(line); // レンジ無し(= 未完了)
const isNotStarted = (line) =>
reUnchecked.test(line) && // 未チェック
!reRange.test(line) && // レンジ無し
!rePlainTime.test(line); // @以外の hh:mm が無い(@hh:mm は許容)
const isCompleted = (line) => reRange.test(line);
// ===== 探索 =====
// 1) 実行中(先頭から)
let targetIdx = lines.findIndex(isRunning);
// 2) 未実行(先頭から)
if (targetIdx === -1) {
targetIdx = lines.findIndex(isNotStarted);
}
// 3) 完了(末尾から)
if (targetIdx === -1) {
for (let i = lines.length - 1; i >= 0; i--) {
if (isCompleted(linesi)) {
targetIdx = i;
break;
}
}
}
// ===== カーソル移動 =====
if (targetIdx !== -1) {
const ch = linestargetIdx.length;
editor.setCursor({ line: targetIdx, ch });
} else {
// 見つからない場合は何もしない(必要なら先頭へ移動等に変更可)
}
%>