Obsidian SimpleTC
作成日: 2025/08/26
タスク開始をワンタップで記録
再実行で終了時刻を確定し、所要時間を自動計算
完了済みのタスクから、再開用の未完タスクを作成
code:js
<%*
async function timestampTool(tp) {
const currentTime = new Date();
const formattedTime = currentTime.toTimeString().slice(0, 5);
// ★ 追加: 差分(分)を計算(翌日またぎ対応)
function diffMinutes(startStr, endStr) {
const sh, sm = startStr.split(":").map(Number); const eh, em = endStr.split(":").map(Number); let d = (eh * 60 + em) - (sh * 60 + sm);
if (d < 0) d += 24 * 60;
return d;
}
const editor = app.workspace.activeLeaf.view.editor;
const cursorLine = editor.getCursor().line;
const currentLineText = editor.getLine(cursorLine);
// 正規化(ダッシュ等の揺れ対策)
const norm = currentLineText.normalize("NFKC");
// 完了判定(元条件+追加条件)
const hasDoneMarkAtStart = /^\s*(?:-\s*\[xX\]\s*|✅✔️\s*)/.test(norm); const hasTimeSpanAtStart = /^\s*(?:-\s*\\s\\s*|-\s*)?(?:\d{2}:\d{2})\s*-–—−\s*\d{2}:\d{2}\b/.test(norm); // 開始のみ(末尾にダッシュが続かない)
// 先頭のインデント/箇条書き/開始時刻をそれぞれ捕捉
const startTimeRegex = /^(\s*)(-\s*\\s\\s*|-\s*)?(\d{2}:\d{2})(?!\s*-–—−)/; let updatedLineText;
if (hasDoneMarkAtStart || hasTimeSpanAtStart) {
// 既に完了扱い:本文を抜き出して新規行(未完に戻す運用は従来どおり)
const body = currentLineText
.replace(/^\s*(?:-\s*\[xX\]\s*|✅✔️\s*)/, "") .replace(/^\s*(?:-\s*\\s\\s*|-\s*)?(?:\d{2}:\d{2})\s*-–—−\s*\d{2}:\d{2}\s*/, "") .trim();
// 先頭にチェックボックスがある場合は未完 (- ) にして複製
const indent = (currentLineText.match(/^\s*/) || "")0; const hasBullet = /^\s*-\s*/.test(currentLineText);
const newPrefix = hasBullet ? ${indent}- [ ] : indent;
const newLineText = ${newPrefix}${body};
editor.setLine(cursorLine, ${currentLineText}\n${newLineText});
// ここは従来どおり次行を編集対象にする運用なら以下でOK。
// ご希望があればここも「行末」固定に変更できます。
editor.setCursor({ line: cursorLine + 1, ch: newLineText.length });
} else if (startTimeRegex.test(currentLineText)) {
// 開始のみ → 終了時刻 + 実績(分)を付与。箇条書きなら - x 化は従来通り const match = currentLineText.match(startTimeRegex);
const indent = match1 || ""; const bullet = match2 || ""; const startHHMM = match3; const bulletCompleted = bullet ? "- x " : ""; // 既存仕様を維持 const actualMin = diffMinutes(startHHMM, formattedTime);
// 開始時刻の直後以降を取得(先頭の実績()があれば除去して上書き)
const afterStart = currentLineText.replace(/^(\s*)(-\s*\\s\\s*|-\s*)?\d{2}:\d{2}\s*/, ""); const bodyClean = afterStart.replace(/^\(\d+\)\s*/, ""); // ★ 既存の (数字) を上書き
updatedLineText = ${indent}${bulletCompleted}${startHHMM}-${formattedTime} (${actualMin}) ${bodyClean};
editor.setLine(cursorLine, updatedLineText);
editor.setCursor({ line: cursorLine, ch: updatedLineText.length });
} else {
// 開始時刻が無い → 行頭に開始時刻を追加(- や - があれば保持)
const listPrefixMatch = currentLineText.match(/^(\s*(?:-\s*\\s\\s*|-\s*)?)/); const listPrefix = listPrefixMatch ? listPrefixMatch1 : ""; const body = currentLineText.slice(listPrefix.length);
updatedLineText = ${listPrefix}${formattedTime} ${body};
editor.setLine(cursorLine, updatedLineText);
// 行末にカーソル
editor.setCursor({ line: cursorLine, ch: updatedLineText.length });
}
}
await timestampTool(tp);
%>