From bbca41c406a122ba30f8d1aab45b492bc44709b8 Mon Sep 17 00:00:00 2001 From: Zodiac Date: Tue, 18 Feb 2025 19:51:12 -0800 Subject: [PATCH] update notes --- plugins/notes.py | 225 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 165 insertions(+), 60 deletions(-) diff --git a/plugins/notes.py b/plugins/notes.py index fd18472..3f109b7 100644 --- a/plugins/notes.py +++ b/plugins/notes.py @@ -6,18 +6,23 @@ IRC Bot Plugin for Note Taking using TinyDB. This plugin provides a single !note command with subcommands to manage both daily and general notes. It supports the following subcommands: - today [...] - View or update today's daily note. + today [--add|--replace] [...] + View or update today's daily note. If content is provided and a note for + today already exists, a warning is shown unless you specify --add (to append) + or --replace (to replace). - daily [--date ] [...] - View or update a daily note for the specified date (default is today). + daily [--date ] [--add|--replace] [...] + View or update a daily note for the specified date (default is today). If + content is provided and a note already exists, a warning is shown unless you + specify --add (to append) or --replace (to replace). general [--tags <tags>] [<content>...] View or update a general note with the given title. Optionally specify tags. list <type> - List all notes of the specified type (either 'daily' or 'general'). + List all notes of the specified type (either 'daily' or 'general'). The + content of each note is displayed truncated. search <type> <keyword> Search for a keyword in notes of the specified type. @@ -34,8 +39,8 @@ Dependencies: - tinydb Author: Your Name -Version: 1.1 -Date: 2025-02-17 +Version: 1.3 +Date: 2025-02-18 """ import re @@ -121,12 +126,27 @@ def default_general_template(title, tags): """ tag_line = f"Tags: {tags}" if tags else "" return f"""# General Note: {title} -{tag_line} -Created on: {now_str()} +{tag_line} Created on: {now_str()} """ +def truncate(text, length=50): + """ + Truncate the text to a specified length, appending "..." if truncated. + + Args: + text (str): The text to truncate. + length (int): Maximum length of the returned text. + + Returns: + str: The truncated text. + """ + if not isinstance(text, str): + text = str(text) + return text if len(text) <= length else text[:length] + "..." + + # ----------------------------------------------------------------------------- # NoteTaking Plugin # ----------------------------------------------------------------------------- @@ -171,17 +191,21 @@ class NoteTaking: @command(aliases=['notes'], public=True, options_first=False, use_shlex=True) async def note(self, mask, target, args): """ - %%note - %%note today [<content>...] - %%note daily [<content>...] [--date=<date>] - %%note general <title> [<content>...] [--tags <tags>] - %%note list <type> + %%note today [--add|--replace] [<content>...] + %%note daily [--date=<date>] [--add|--replace] [<content>...] + %%note general <title> [--tags=<tags>] [<content>...] + %%note list [<type>] %%note search <type> <keyword> %%note summary + %%note """ # If no subcommand is provided, show the help message. if not any(args.get(key) for key in ('today', 'daily', 'general', 'list', 'search', 'summary')): - self._show_help(target) + # If there's content provided without a subcommand, treat it as a daily note update. + if args.get('<content>'): + await self._note_today(mask, target, args) + else: + self._show_help(target) return try: @@ -208,10 +232,10 @@ class NoteTaking: help_lines = [ ircstyle.style("Usage: !note <subcommand> [options]", fg="red", bold=True), "Subcommands:", - f"{ircstyle.style(' today', fg='yellow')} - View or update today's daily note.", - f"{ircstyle.style(' daily [--date <date>]', fg='yellow')} - View or update a daily note for a specific date (default is today).", - f"{ircstyle.style(' general <title> [--tags <tags>]', fg='yellow')} - View or update a general note with the given title. Optionally, specify tags.", - f"{ircstyle.style(' list [daily|general]', fg='yellow')} - List all notes of a specific type.", + f"{ircstyle.style(' today [--add|--replace] [<content>...]', fg='yellow')} - View or update today's daily note.", + f"{ircstyle.style(' daily [--date <date>] [--add|--replace] [<content>...]', fg='yellow')} - View or update a daily note for a specific date (default is today).", + f"{ircstyle.style(' general <title> [--tags <tags>] [<content>...]', fg='yellow')} - View or update a general note with the given title. Optionally, specify tags.", + f"{ircstyle.style(' list [daily|general]', fg='yellow')} - List all notes of a specific type with truncated content.", f"{ircstyle.style(' search <type> <keyword>', fg='yellow')} - Search for a keyword in notes of a specific type.", f"{ircstyle.style(' summary', fg='yellow')} - Display a summary of note counts.", ] @@ -223,7 +247,9 @@ class NoteTaking: """ Handle the 'today' subcommand for daily notes. - If content is provided, update today's note; otherwise, display it. + If content is provided, update today's note. + If a note already exists and content is provided, warn the user unless + --add or --replace is specified. """ day = today_str() content_list = args.get('<content>') @@ -231,21 +257,50 @@ class NoteTaking: note = self._get_daily_note(day) if content_list: new_content = " ".join(content_list) - if note: - self.daily_table.update( - {'content': new_content, 'updated': now_str()}, - self.User.date == day + # Check if both flags are provided + if args.get('--add') and args.get('--replace'): + self.bot.privmsg( + target, + ircstyle.style("❌ Error: Cannot use both --add and --replace simultaneously. Please choose one.", fg="red", bold=True) ) + return + + if note: + # If note exists but neither flag is provided, warn the user. + if not (args.get('--add') or args.get('--replace')): + warning = ircstyle.style( + f"⚠️ Warning: Daily note for {day} already exists. Use --add to append to it or --replace to overwrite it.", fg="red", bold=True + ) + self.bot.privmsg(target, warning) + return + if args.get('--add'): + appended_content = note.get('content') + "\n" + new_content + self.daily_table.update( + {'content': appended_content, 'updated': now_str()}, + self.User.date == day + ) + msg = ircstyle.style("✅ ", fg="green") + ircstyle.style( + f"Daily note for {day} updated (content added).", fg="blue", bold=True + ) + elif args.get('--replace'): + self.daily_table.update( + {'content': new_content, 'updated': now_str()}, + self.User.date == day + ) + msg = ircstyle.style("✅ ", fg="green") + ircstyle.style( + f"Daily note for {day} replaced.", fg="blue", bold=True + ) else: + # No existing note; create a new one. self.daily_table.insert({ 'date': day, 'content': new_content, 'created': now_str(), 'updated': now_str() }) - msg = ircstyle.style("✅ ", fg="green") + ircstyle.style( - f"Daily note for {day} updated.", fg="blue", bold=True - ) + msg = ircstyle.style("✅ ", fg="green") + ircstyle.style( + f"Daily note for {day} created.", fg="blue", bold=True + ) else: if not note: default_content = self.daily_template(day) @@ -272,7 +327,9 @@ class NoteTaking: """ Handle the 'daily' subcommand for daily notes with an optional date. - If content is provided, update the note; otherwise, display it. + If content is provided, update the note. + If a note already exists and content is provided, warn the user unless + --add or --replace is specified. """ day = args.get('--date') or today_str() try: @@ -290,21 +347,49 @@ class NoteTaking: note = self._get_daily_note(day) if content_list: new_content = " ".join(content_list) - if note: - self.daily_table.update( - {'content': new_content, 'updated': now_str()}, - self.User.date == day + # Check if both flags are provided + if args.get('--add') and args.get('--replace'): + self.bot.privmsg( + target, + ircstyle.style("❌ Error: Cannot use both --add and --replace simultaneously. Please choose one.", fg="red", bold=True) ) + return + + if note: + if not (args.get('--add') or args.get('--replace')): + self.bot.privmsg( + target, + ircstyle.style(f"⚠️ Warning: Daily note for {day} already exists. Use --add to append or --replace to overwrite.", fg="red", bold=True) + ) + return + if args.get('--add'): + appended_content = note.get('content') + "\n" + new_content + self.daily_table.update( + {'content': appended_content, 'updated': now_str()}, + self.User.date == day + ) + msg = ircstyle.style("✅ ", fg="green") + ircstyle.style( + f"Daily note for {day} updated (content added).", fg="blue", bold=True + ) + elif args.get('--replace'): + self.daily_table.update( + {'content': new_content, 'updated': now_str()}, + self.User.date == day + ) + msg = ircstyle.style("✅ ", fg="green") + ircstyle.style( + f"Daily note for {day} replaced.", fg="blue", bold=True + ) else: + # Create new note if none exists. self.daily_table.insert({ 'date': day, 'content': new_content, 'created': now_str(), 'updated': now_str() }) - msg = ircstyle.style("✅ ", fg="green") + ircstyle.style( - f"Daily note for {day} updated.", fg="blue", bold=True - ) + msg = ircstyle.style("✅ ", fg="green") + ircstyle.style( + f"Daily note for {day} created.", fg="blue", bold=True + ) else: if not note: default_content = self.daily_template(day) @@ -410,7 +495,7 @@ class NoteTaking: async def _note_list(self, target, args): """ - Handle the 'list' subcommand to list notes. + Handle the 'list' subcommand to list notes with truncated content. Usage: %%note list [<type>] @@ -420,43 +505,63 @@ class NoteTaking: note_type = args.get('<type>') try: if not note_type: - # List both daily and general notes + # List both daily and general notes with content truncated. daily_notes = self.daily_table.all() general_notes = self.general_table.all() - # Filter valid daily notes - valid_daily_dates = [n.get('date') for n in daily_notes if isinstance(n.get('date'), str)] - # Filter valid general notes - valid_general_titles = [n.get('title') for n in general_notes if isinstance(n.get('title'), str)] - - if not valid_daily_dates and not valid_general_titles: + if not daily_notes and not general_notes: msg = ircstyle.style("No notes found.", fg="red", bold=True) else: - msg = ircstyle.style("📝 All Notes:", fg="blue", bold=True) + "\n" - if valid_daily_dates: - msg += ircstyle.style("📅 Daily Notes:", fg="yellow", bold=True) + "\n" - msg += "\n".join([f"• {date}" for date in sorted(valid_daily_dates)]) + "\n" - if valid_general_titles: - msg += ircstyle.style("📋 General Notes:", fg="cyan", bold=True) + "\n" - msg += "\n".join([f"• {title}" for title in sorted(valid_general_titles)]) + msg_lines = [ircstyle.style("📝 All Notes:", fg="blue", bold=True)] + if daily_notes: + msg_lines.append(ircstyle.style("📅 Daily Notes:", fg="yellow", bold=True)) + # Sort daily notes by date. + daily_sorted = sorted( + [n for n in daily_notes if isinstance(n.get('date'), str)], + key=lambda x: x['date'] + ) + for note in daily_sorted: + date_str = note.get('date') + snippet = truncate(note.get('content', '')) + msg_lines.append(f" • {ircstyle.style(date_str, fg='green')}: {ircstyle.style(snippet, fg='white')}") + if general_notes: + msg_lines.append(ircstyle.style("📋 General Notes:", fg="cyan", bold=True)) + # Sort general notes by title. + general_sorted = sorted( + [n for n in general_notes if isinstance(n.get('title'), str)], + key=lambda x: x['title'] + ) + for note in general_sorted: + title = note.get('title') + snippet = truncate(note.get('content', '')) + msg_lines.append(f" • {ircstyle.style(title, fg='green')}: {ircstyle.style(snippet, fg='white')}") + msg = "\n".join(msg_lines) elif note_type == 'daily': notes = self.daily_table.all() - # Filter only notes with a valid date string - valid_dates = [n.get('date') for n in notes if isinstance(n.get('date'), str)] - if not valid_dates: + valid_notes = [n for n in notes if isinstance(n.get('date'), str)] + if not valid_notes: msg = ircstyle.style("No daily notes found.", fg="red", bold=True) else: - dates = sorted(valid_dates) - msg = ircstyle.style("📅 Daily Notes:", fg="blue", bold=True) + "\n" - msg += "\n".join([f"• {date}" for date in dates]) + msg_lines = [ircstyle.style("📅 Daily Notes:", fg="blue", bold=True)] + daily_sorted = sorted(valid_notes, key=lambda x: x['date']) + for note in daily_sorted: + date_str = note.get('date') + snippet = truncate(note.get('content', '')) + msg_lines.append(f" • {ircstyle.style(date_str, fg='green')}: {ircstyle.style(snippet, fg='white')}") + msg = "\n".join(msg_lines) elif note_type == 'general': notes = self.general_table.all() - if not notes: + valid_notes = [n for n in notes if isinstance(n.get('title'), str)] + if not valid_notes: msg = ircstyle.style("No general notes found.", fg="red", bold=True) else: - titles = sorted(n['title'] for n in notes if isinstance(n.get('title'), str)) - msg = ircstyle.style("📋 General Notes:", fg="blue", bold=True) + "\n" - msg += "\n".join([f"• {title}" for title in titles]) + msg_lines = [ircstyle.style("📋 General Notes:", fg="blue", bold=True)] + general_sorted = sorted(valid_notes, key=lambda x: x['title']) + for note in general_sorted: + title = note.get('title') + snippet = truncate(note.get('content', '')) + msg_lines.append(f" • {ircstyle.style(title, fg='green')}: {ircstyle.style(snippet, fg='white')}") + msg = "\n".join(msg_lines) else: msg = ircstyle.style("Usage: !note list [daily|general]", fg="red", bold=True) for line in msg.split('\n'):