//! `koh flag` — mark a save unsafe, clear the mark, or list what is marked. //! //! A flag is an event, not a column: save records are write-once, and clearing //! a flag is itself an event, so flagging stays undoable and syncs like //! everything else. module cli import json import src.events import src.fmt import src.history import src.storage pub fn cmd_flag(raw []string) int { args := parse('flag', raw, Options{ values: ['reason'] flags: ['clear', 'json'] }) or { return usage_error(err.msg()) } store := open_store() or { return refuse(args.json(), err.msg()) } defer { store.close() } if args.positional.len == 0 && !args.flag('clear') { return list_flags(store, args) } id := args.positional_at(0) if id == '' { return usage_error('flag needs a save ID, or nothing at all to list flagged saves') } save := history.resolve(store, id) or { return refuse(args.json(), err.msg()) } if args.flag('clear') { events.clear_flag(store, save.id) or { return refuse(args.json(), err.msg()) } if args.json() { emit_json(json.encode(FlagJson{ save_id: save.id flagged: false reason: '' })) return 0 } ok('cleared the flag on [${save.id}]') return 0 } reason := args.value('reason') events.flag(store, save.id, reason) or { return refuse(args.json(), err.msg()) } if args.json() { emit_json(json.encode(FlagJson{ save_id: save.id flagged: true reason: reason })) return 0 } ok('flagged [${save.id}]${if reason != '' { ' — ${reason}' } else { '' }}') return 0 } fn list_flags(store &storage.Store, args Args) int { flags := events.latest_flags(store) or { return refuse(args.json(), err.msg()) } mut flagged := []FlagJson{} for save_id, state in flags { if !state.flagged { continue } flagged << FlagJson{ save_id: save_id flagged: true reason: state.reason } } flagged.sort(a.save_id < b.save_id) if args.json() { emit_json(json.encode(FlagListJson{ flagged: flagged })) return 0 } if flagged.len == 0 { ok('nothing is flagged') return 0 } for entry in flagged { save := history.by_id(store, entry.save_id) or { continue } mut line := ' ${fmt.amber('⚑')} ${fmt.dim('[' + save.id + ']')} ${fmt.stamp(save.created_at)} ${save.message}' if entry.reason != '' { line += ' ${fmt.dim(entry.reason)}' } println(line) } return 0 } struct FlagJson { save_id string flagged bool reason string } struct FlagListJson { flagged []FlagJson }