diff --git a/.editorconfig b/.editorconfig index 1c6314a..9608d30 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,7 +1,7 @@ root = true [*] -indent_style = tab +indent_style = space end_of_line = lf charset = utf-8 trim_trailing_whitespace = true diff --git a/source/app.js b/source/app.js index 3cffe55..707f75f 100644 --- a/source/app.js +++ b/source/app.js @@ -2,39 +2,11 @@ import React, { useState, useEffect } from "react"; import { render, Box, Text, useApp, useInput } from "ink"; import fs from "fs"; -import path from "path"; import { execSync, spawn } from "child_process"; -import { fileURLToPath } from "url"; +import { loadTasks, saveTasks, commitAndPushTasks, pullTasks } from "./tasks.js"; import { Tabs, Tab } from 'ink-tab'; import Scrollbar from "./scrollbar.js"; -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); -const TASK_FILE = path.join(__dirname, "tasks.json"); -const loadTasks = () => { - try { - return ensureIds(JSON.parse(fs.readFileSync(TASK_FILE, "utf8"))); - } catch { - return []; - } -}; - -const ensureIds = (tasks) => { - return tasks.map(task => { - if (!task.id) { - task.id = randomId(); - } - if (task.subtasks && task.subtasks.length > 0) { - task.subtasks = ensureIds(task.subtasks); - } - return task; - }); -}; - -const saveTasks = (tasks) => { - const updatedTasks = ensureIds(tasks); - fs.writeFileSync(TASK_FILE, JSON.stringify(updatedTasks, null, 2)); -}; const countIncompleteSubtasks = (task) => { if (!task.subtasks || task.subtasks.length === 0) return 0; @@ -139,13 +111,13 @@ export default function TaskApp() { fs.writeFileSync(tempFile, task.content || task.name); try { // Run Neovim in a tmux split and use "wait-for" to track when it closes - execSync(`tmux split-window -h 'nvim ${tempFile}; tmux wait-for -S nvim_done'`); + execSync(`tmux split-window -h 'n ${tempFile}; tmux wait-for -S nvim_done'`); // Wait for Neovim to exit (blocks execution until the user quits Neovim) execSync("tmux wait-for nvim_done"); } catch (error) { // If tmux is not available, open Neovim normally - spawn("nvim", [tempFile], { stdio: "inherit" }); + spawn("n", [tempFile], { stdio: "inherit" }); } const editedTask = fs.readFileSync(tempFile, "utf8").trim(); @@ -303,6 +275,18 @@ export default function TaskApp() { setCutTask(null); log(`Moved task: ${cutTask.task.name}`); } + + if (input === "S") { + const confirmation = execSync(`echo "push\npull" | fzf --prompt 'Sync'`, { stdio: "pipe" }).toString().trim(); + if (confirmation === "push") { + commitAndPushTasks(log) + } + + if (confirmation === "pull") { + pullTasks(log) + setTasks(loadTasks(), log) + } + } if (input === "?") { log("=========================="); log("Keybindings:"); @@ -314,6 +298,7 @@ export default function TaskApp() { log("a - Add task"); log("s - Add subtask"); log("e - Edit task in Neovim"); + log("S - Sync (Push/Pull)"); log("space - Toggle completion"); log("/ - Search"); log("? - Show help"); diff --git a/source/tasks.js b/source/tasks.js new file mode 100644 index 0000000..7ddbc70 --- /dev/null +++ b/source/tasks.js @@ -0,0 +1,59 @@ + +import fs from "fs"; +import path from "path"; +if (!process.env.TD_TASK_DIR) { + throw new Error("Environment variable TD_TASK_DIR is not defined"); +} +const TASK_FILE = path.join(process.env.TD_TASK_DIR, "tasks.json"); + + +const ensureIds = (tasks) => { + return tasks.map(task => { + if (!task.id) { + task.id = randomId(); + } + if (task.subtasks && task.subtasks.length > 0) { + task.subtasks = ensureIds(task.subtasks); + } + return task; + }); +}; + +export function loadTasks() { + try { + return ensureIds(JSON.parse(fs.readFileSync(TASK_FILE, "utf8"))); + } catch { + return []; + } +}; + +export function saveTasks(tasks) { + const updatedTasks = ensureIds(tasks); + fs.writeFileSync(TASK_FILE, JSON.stringify(updatedTasks, null, 2)); +}; + +import { execSync } from "child_process"; + +export function commitAndPushTasks(log) { + const currentDateTime = new Date().toISOString(); + const commitMessage = `Update tasks.json - ${currentDateTime}`; + + try { + execSync(`git -C ${process.env.TD_TASK_DIR} add tasks.json`, { stdio: "pipe" }); + execSync(`git -C ${process.env.TD_TASK_DIR} commit -m "${commitMessage}"`, { stdio: "pipe" }); + execSync(`git -C ${process.env.TD_TASK_DIR} push origin`, { stdio: "pipe" }); + } catch (error) { + log("Failed to commit and push tasks.json:", error); + } +} + + +export function pullTasks() { + + try { + execSync(`git -C ${process.env.TD_TASK_DIR} restore tasks.json`, { stdio: "pipe" }); + execSync(`git -C ${process.env.TD_TASK_DIR} pull`, { stdio: "pipe" }); + } catch (error) { + log("Failed to pull tasks.json:", error); + } +}