From 282c8ebfae215234c1d9bb52e6a7b014e07bf4be Mon Sep 17 00:00:00 2001 From: Himanshu Mishra Date: Fri, 18 Jul 2025 18:05:44 +0530 Subject: [PATCH] Add notes and set features --- README.md | 1 + keep/commands/cmd_new.py | 65 ++++++++++++++++++++++++++++++++-------- keep/utils.py | 22 ++++++++++++++ 3 files changed, 75 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 85a52cb8..e68d1e46 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ is only place where he\'ll ever have use it? ## Features - Save a new command with a brief description +- Save notes or command sets with `keep new notes` and `keep new set` - Search the saved commands using powerful patterns - Save the commands as a secret GitHub gist - Use `keep push` and `keep pull` to sync the commands between GitHub diff --git a/keep/commands/cmd_new.py b/keep/commands/cmd_new.py index 9cd05a79..cde67095 100644 --- a/keep/commands/cmd_new.py +++ b/keep/commands/cmd_new.py @@ -1,19 +1,58 @@ import click -from keep import cli, utils +from keep import cli as kcli, utils -@click.command("new", short_help="Saves a new command.") + +@click.group("new", short_help="Create a new entry.", invoke_without_command=True) @click.option("--cmd", help="The command to save") @click.option("--desc", help="The description of the command") @click.option("--alias", default="", help="The alias of the command") -@cli.pass_context -def cli(ctx, cmd, desc, alias): - """Saves a new command""" - if not cmd: - cmd = click.prompt("Command") - if not desc: - desc = click.prompt("Description") - if not alias: - alias = click.prompt("Alias (optional)", default="") - utils.save_command(cmd, desc, alias) +@kcli.pass_context +def cli(kctx, cmd, desc, alias): + """Saves a new command, note or command set.""" + ctx = click.get_current_context() + if ctx.invoked_subcommand is None: + if not cmd: + cmd = click.prompt("Command") + if not desc: + desc = click.prompt("Description") + if not alias: + alias = click.prompt("Alias (optional)", default="") + utils.save_command(cmd, desc, alias) + utils.log(kctx, f"Saved the new command - {cmd} - with the description - {desc}.") + + +@cli.command("notes", short_help="Saves a new note.") +@click.option("--name", help="Name of the note") +@click.option("--text", help="Text of the note") +@kcli.pass_context +def notes(kctx, name, text): + if not name: + name = click.prompt("Name") + if not text: + template = "# Write your note below\n" + edited = click.edit(template) + if not edited: + click.echo("No note provided.") + return + text = "\n".join([line for line in edited.splitlines() if not line.startswith("#")]) + utils.save_note(name, text) + utils.log(kctx, f"Saved the note - {name}.") + + +@cli.command("set", short_help="Saves a new set of commands.") +@click.option("--name", help="Name of the set") +@click.option("--commands", multiple=True, help="Commands in the set") +@kcli.pass_context +def set_(kctx, name, commands): + if not name: + name = click.prompt("Name") + if not commands: + template = "# Enter commands one per line\n" + edited = click.edit(template) + if not edited: + click.echo("No commands provided.") + return + commands = [line for line in edited.splitlines() if not line.startswith("#") and line.strip()] + utils.save_command_set(name, list(commands)) + utils.log(kctx, f"Saved command set - {name}.") - utils.log(ctx, "Saved the new command - {} - with the description - {}.".format(cmd, desc)) diff --git a/keep/utils.py b/keep/utils.py index 83367144..742cdaa9 100644 --- a/keep/utils.py +++ b/keep/utils.py @@ -193,6 +193,28 @@ def save_command(cmd, desc, alias=""): f.write(json.dumps(commands)) +def save_note(name, note): + """Save a note text with a given name.""" + json_path = os.path.join(dir_path, 'notes.json') + notes = {} + if os.path.exists(json_path): + notes = json.loads(open(json_path, 'r').read()) + notes[name] = note + with open(json_path, 'w') as f: + f.write(json.dumps(notes)) + + +def save_command_set(name, commands): + """Save a set of commands under a name.""" + json_path = os.path.join(dir_path, 'sets.json') + sets = {} + if os.path.exists(json_path): + sets = json.loads(open(json_path, 'r').read()) + sets[name] = commands + with open(json_path, 'w') as f: + f.write(json.dumps(sets)) + + def read_commands(): json_path = os.path.join(dir_path, 'commands.json') if not os.path.exists(json_path):