this repo has no description

Add human-readable keyword and flag color formatting

- Added functions to format message keywords and flag colors in a human-readable way
- Updated fastmail_list to use these functions for better display of labels
- Enhanced flag_color_test with a demo of the formatting functionality
- Updated AGENT.md to mark task as completed

🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>

+114 -9
+2 -1
AGENT.md
··· 44 44 also list the JMAP labels associated with each message. 45 45 9. DONE Read the mailbox attribute spec in specs/ and add a typed interface to the 46 46 JMAP labels defined in there. 47 - 10. Add an OCaml interface to compose result references together explicitly into a 47 + 10. DONE Integrate the human-readable keyword and label printing into fastmail-list. 48 + 11. Add an OCaml interface to compose result references together explicitly into a 48 49 single request, from reading the specs.
+3 -7
bin/fastmail_list.ml
··· 39 39 (* Format labels/keywords if requested *) 40 40 let labels_str = 41 41 if show_labels then 42 - let active_keywords = 43 - List.filter_map (fun (keyword, active) -> 44 - if active then Some (Jmap_mail.Json.string_of_keyword keyword) else None 45 - ) email.keywords 46 - in 47 - if List.length active_keywords > 0 then 48 - " [" ^ String.concat ", " active_keywords ^ "]" 42 + let formatted = Jmap_mail.Types.format_email_keywords email.keywords in 43 + if formatted <> "" then 44 + " [" ^ formatted ^ "]" 49 45 else 50 46 "" 51 47 else
+23 -1
bin/flag_color_test.ml
··· 85 85 86 86 Printf.printf "\n" 87 87 88 + (** Demonstrate formatting functionality *) 89 + let demo_formatting () = 90 + Printf.printf "Keyword Formatting Demo:\n"; 91 + Printf.printf "======================\n"; 92 + 93 + (* Create a sample email with various keywords *) 94 + let sample_keywords = [ 95 + (Flagged, true); (* Standard flag *) 96 + (Custom "$MailFlagBit0", true); (* Flag color bit *) 97 + (Custom "$MailFlagBit2", true); (* Flag color bit *) 98 + (Custom "$notify", true); (* Message keyword *) 99 + (Custom "$followed", true); (* Message keyword *) 100 + (Custom "$hasattachment", true); (* Message keyword *) 101 + (Seen, false); (* Inactive keyword *) 102 + (Custom "$random", true); (* Unknown keyword *) 103 + ] in 104 + 105 + (* Test formatted output *) 106 + let formatted = format_email_keywords sample_keywords in 107 + Printf.printf "Formatted keywords: %s\n\n" formatted 108 + 88 109 (** Main entry point *) 89 110 let () = 90 111 demo_flag_colors (); 91 112 demo_message_keywords (); 92 - demo_mailbox_attributes () 113 + demo_mailbox_attributes (); 114 + demo_formatting ()
+77
lib/jmap_mail.ml
··· 1025 1025 | "Scheduled" -> Scheduled 1026 1026 | "Memos" -> Memos 1027 1027 | s -> OtherAttribute s 1028 + 1029 + (** Get a human-readable representation of a flag color *) 1030 + let human_readable_flag_color = function 1031 + | Red -> "Red" 1032 + | Orange -> "Orange" 1033 + | Yellow -> "Yellow" 1034 + | Green -> "Green" 1035 + | Blue -> "Blue" 1036 + | Purple -> "Purple" 1037 + | Gray -> "Gray" 1038 + 1039 + (** Get a human-readable representation of a message keyword *) 1040 + let human_readable_message_keyword = function 1041 + | Notify -> "Notify" 1042 + | Muted -> "Muted" 1043 + | Followed -> "Followed" 1044 + | Memo -> "Memo" 1045 + | HasMemo -> "Has Memo" 1046 + | HasAttachment -> "Has Attachment" 1047 + | HasNoAttachment -> "No Attachment" 1048 + | AutoSent -> "Auto Sent" 1049 + | Unsubscribed -> "Unsubscribed" 1050 + | CanUnsubscribe -> "Can Unsubscribe" 1051 + | Imported -> "Imported" 1052 + | IsTrusted -> "Trusted" 1053 + | MaskedEmail -> "Masked Email" 1054 + | New -> "New" 1055 + | MailFlagBit0 | MailFlagBit1 | MailFlagBit2 -> "Flag Bit" 1056 + | OtherKeyword s -> s 1057 + 1058 + (** Format email keywords into a human-readable string representation *) 1059 + let format_email_keywords keywords = 1060 + (* Get flag color if present *) 1061 + let color_str = 1062 + match get_flag_color keywords with 1063 + | Some color -> human_readable_flag_color color 1064 + | None -> "" 1065 + in 1066 + 1067 + (* Get standard JMAP keywords *) 1068 + let standard_keywords = List.filter_map (fun (kw, active) -> 1069 + if not active then None 1070 + else match kw with 1071 + | Flagged -> Some "Flagged" 1072 + | Answered -> Some "Answered" 1073 + | Draft -> Some "Draft" 1074 + | Forwarded -> Some "Forwarded" 1075 + | Phishing -> Some "Phishing" 1076 + | Junk -> Some "Junk" 1077 + | NotJunk -> Some "Not Junk" 1078 + | Seen -> Some "Seen" 1079 + | Unread -> Some "Unread" 1080 + | _ -> None 1081 + ) keywords in 1082 + 1083 + (* Get message keywords *) 1084 + let message_keywords = List.filter_map (fun (kw, active) -> 1085 + if not active then None 1086 + else match kw with 1087 + | Custom s -> 1088 + (* Try to parse as message keyword *) 1089 + let message_kw = message_keyword_of_string s in 1090 + (match message_kw with 1091 + | OtherKeyword _ -> None 1092 + | MailFlagBit0 | MailFlagBit1 | MailFlagBit2 -> None 1093 + | kw -> Some (human_readable_message_keyword kw)) 1094 + | _ -> None 1095 + ) keywords in 1096 + 1097 + (* Combine all human-readable labels *) 1098 + let all_parts = 1099 + (if color_str <> "" then [color_str] else []) @ 1100 + standard_keywords @ 1101 + message_keywords 1102 + in 1103 + 1104 + String.concat ", " all_parts 1028 1105 end 1029 1106 1030 1107 (** {1 JSON serialization} *)
+9
lib/jmap_mail.mli
··· 909 909 910 910 (** Parse a string into a mailbox attribute *) 911 911 val mailbox_attribute_of_string : string -> mailbox_attribute 912 + 913 + (** Get a human-readable representation of a flag color *) 914 + val human_readable_flag_color : flag_color -> string 915 + 916 + (** Get a human-readable representation of a message keyword *) 917 + val human_readable_message_keyword : message_keyword -> string 918 + 919 + (** Format email keywords into a human-readable string representation *) 920 + val format_email_keywords : (keyword * bool) list -> string 912 921 end 913 922 914 923 (** {1 JSON serialization} *)