% This particular email-editing mode borrows ideas from several other % such modes from contributers such as % % Morten Bo Johansen -> email % Paul Boekholt % Johann Botha -> muttmail % Ulli Horlacher % Abraham vd Merwe % Thomas Roessler % % To use this mode for editing a mail message from mutt, slrn, etc, set % the editor variable to: % % "jed %s -tmp --mailedit-mode" % % Variables supported by the mode include: % % MailEdit_Fcc % MailEdit_Reply_To % MailEdit_Max_Signature_Lines % MailEdit_Quote_Chars, % % The colors may be controlled by % % MailEdit_Quote_Color % MailEdit_Signature_Color % MailEdit_To_Color % MailEdit_Subject_Color % MailEdit_From_Color % MailEdit_Header_Color % % via, e.g., set_color ("MailEdit_Header_Color", "red", "black"); % % The function mailedit_mode calls mailedit_mode_hook. % require ("mailutils"); custom_variable ("MailEdit_Fcc", NULL); custom_variable ("MailEdit_Reply_To", NULL); custom_variable ("MailEdit_Max_Signature_Lines", 4); custom_variable ("MailEdit_Quote_Chars", ">:|"); custom_color ("MailEdit_Quote_Color", get_color ("string")); custom_color ("MailEdit_Signature_Color", get_color ("preprocess")); custom_color ("MailEdit_From_Color", get_color ("keyword")); custom_color ("MailEdit_To_Color", get_color ("keyword")); custom_color ("MailEdit_Subject_Color", get_color ("keyword")); custom_color ("MailEdit_Header_Color", get_color ("keyword1")); autoload ("mailalias_expand", "mailalias"); private variable Header_Color = color_number ("MailEdit_Header_Color"); private variable Quote_Color = color_number ("MailEdit_Quote_Color"); private variable Signature_Color = color_number ("MailEdit_Signature_Color"); private variable From_Color = color_number ("MailEdit_From_Color"); private variable To_Color = color_number ("MailEdit_To_Color"); private variable Subject_Color = color_number ("MailEdit_Subject_Color"); private define find_header_keyword_start () { do { bol_skip_white (); if (bolp ()) return; } while (up(1)); bol (); } % If the header does not exist, it will be created. */ private define goto_header (header) { if (-1 == mailutils_narrow_to_header ()) return -1; variable exists = bol_fsearch (header); widen_region (); if (exists == 0) { () = mailutils_find_header_separator (); % Do it this way to avoid moving the line mark go_left (1); vinsert ("\n%s ", header); return 0; } go_right (strlen (header)); skip_white (); return 0; } private define add_xxx_header (header, value) { if (value == NULL) return; variable exists = mailutils_get_keyword_value (header); if ((exists != NULL) and (exists != "")) return; push_spot (); if (0 == goto_header (header)) insert (value); pop_spot (); } % If not found, the point is left at eob private define find_signature_start () { eob (); variable line = what_line (); !if (bol_bsearch ("-- \n")) return 0; if (line - what_line () > MailEdit_Max_Signature_Lines) { eob (); return 0; } return 1; } private define in_signature () { variable m = create_user_mark (); EXIT_BLOCK { goto_user_mark (m); } !if (find_signature_start ()) return 0; return m >= create_user_mark (); } private define in_header () { variable m = create_user_mark (); variable ih = 0; if (mailutils_find_header_separator ()) ih = (m <= create_user_mark ()); goto_user_mark (m); return ih; } private define in_mail_body () { if (in_header ()) return 0; return not in_signature (); } private define line_is_quoted () { push_spot(); bol_skip_white (); variable c = what_column (); skip_chars (MailEdit_Quote_Chars); c = what_column () - c; pop_spot (); return c; } % Moves to bol, skips the quote characters leaving the point and returns their number private define count_quotes () { bol_skip_white (); variable count = 0; forever { push_mark (); skip_chars (MailEdit_Quote_Chars); variable dcount = strlen (bufsubstr ()); !if (dcount) break; count += dcount; !if (looking_at (" ")) break; go_right_1 (); } return count; } private define skip_quotes () { bol_skip_white (); skip_chars (MailEdit_Quote_Chars); } private define extract_quotes () { push_spot (); () = count_quotes (); push_mark (); bol (); bufsubstr (); % on stack pop_spot (); } % What constitutes a paragraph? private define mark_paragraph () { !if (in_mail_body ()) { push_mark (); return; } push_spot (); % Goto paragraph start variable nquotes = count_quotes (); while (up_1 ()) { if (nquotes == count_quotes ()) { skip_white (); !if (eolp ()) continue; } go_down_1 (); break; } bol (); push_mark (); % Now goto end pop_spot (); eol (); while (down_1 ()) { if (nquotes == count_quotes ()) { skip_white (); !if (eolp ()) { eol (); continue; } } bol (); break; } if (in_signature ()) { () = find_signature_start (); } } private define format_paragraph_hook (); private define format_header () { push_spot (); find_header_keyword_start (); push_mark (); while (down_1 ()) { skip_white (); if (bolp ()) break; } narrow_to_region (); bob (); unset_buffer_hook ("format_paragraph_hook"); call ("format_paragraph"); set_buffer_hook ("format_paragraph_hook", &format_paragraph_hook); bob (); while (down_1 () and not (eobp ())) insert (" "); eob (); !if (bolp ()) newline (); widen_region (); pop_spot (); } private define format_paragraph_hook () { if (in_header ()) return format_header (); if (in_signature ()) return; % In the body push_spot (); variable nquotes = count_quotes (); variable quotes = extract_quotes (); mark_paragraph (); narrow_to_region (); bob (); if (nquotes) while (nquotes == count_quotes ()) { push_mark (); bol (); del_region (); !if (down_1 ()) break; } pop_spot (); unset_buffer_hook ("format_paragraph_hook"); call ("format_paragraph"); set_buffer_hook ("format_paragraph_hook", &format_paragraph_hook); push_spot (); eob (); if (not bolp ()) newline (); if (nquotes) { bob (); do { insert (quotes); } while (down_1 () and not (eobp ())); } pop_spot (); widen_region (); } private define is_paragraph_separator () { !if (in_mail_body ()) return 1; if (line_is_quoted ()) return 1; bol_skip_white (); return eolp (); } private define wrap_hook () { push_spot (); EXIT_BLOCK { pop_spot (); } if (in_header ()) { bol_trim (); insert (" "); trim (); } if (in_mail_body ()) { #iftrue indent_line (); #else go_up_1 (); bol_skip_white (); variable col = what_column (); go_down_1 (); bol_trim (); whitespace (col - 1); #endif return; } } private define add_fcc () { add_xxx_header ("Fcc:", MailEdit_Fcc); } private define add_replyto () { add_xxx_header ("Reply-To:", MailEdit_Reply_To); } private define mark_header_separator () { !if (mailutils_find_header_separator ()) return; %set_line_readonly (1); } private variable Header_Color_Map = Assoc_Type[Int_Type, Header_Color]; Header_Color_Map["TO"] = To_Color; Header_Color_Map["CC"] = To_Color; Header_Color_Map["BCC"] = To_Color; Header_Color_Map["SUBJECT"] = Subject_Color; Header_Color_Map["FROM"] = From_Color; private define color_header_line () { push_spot (); find_header_keyword_start (); push_mark (); () = ffind (":"); variable color = Header_Color_Map[strup (bufsubstr())]; pop_spot (); set_line_color (color); } private define color_buffer (min_line, max_line) { push_spot (); EXIT_BLOCK { pop_spot (); } % Optimization for the most common case if (min_line == max_line) { goto_line (min_line); if (in_header ()) { bol (); color_header_line (); return; } if (in_signature ()) { set_line_color (Signature_Color); return; } if (line_is_quoted ()) { set_line_color (Quote_Color); return; } set_line_color (0); return; } variable header_line, signature_line; if (mailutils_find_header_separator ()) header_line = what_line (); else header_line = 0; if (find_signature_start ()) signature_line = what_line (); else signature_line = max_line + 1; goto_line (min_line); if (max_line < header_line) header_line = max_line + 1; if (min_line <= header_line) { loop (header_line - min_line) { color_header_line (); %set_line_color (Header_Color); go_down_1 (); } % skip header go_down_1 (); min_line = header_line; min_line++; } if (max_line < signature_line) signature_line = max_line + 1; loop (signature_line - min_line) { if (line_is_quoted ()) set_line_color (Quote_Color); else set_line_color (0); go_down_1 (); } min_line = signature_line; loop (max_line - min_line + 1) { set_line_color (Signature_Color); go_down_1 (); } } private define newline_indent_hook () { if (line_is_quoted ()) { !if (bolp () or eolp ()) { variable quotes = extract_quotes (); insert ("\n\n\n"); insert (quotes); call ("format_paragraph"); go_up (2); return; } } newline (); indent_line (); } !if (keymap_p ("mailedit")) make_keymap ("mailedit"); public define mailedit_mode () { mark_header_separator (); add_fcc (); add_replyto (); variable start_mark = NULL; bob (); if (bol_fsearch ("To: ")) { go_right (3); skip_chars ("\t "); if (eolp ()) start_mark = create_user_mark (); } if (start_mark == NULL) { if (mailutils_find_header_separator ()) { go_down (2); start_mark = create_user_mark (); } } bob (); if (start_mark != NULL) goto_user_mark (start_mark); set_buffer_modified_flag (0); use_keymap ("mailedit"); set_mode ("mailedit", 1); unset_buffer_hook (""); %set_buffer_hook ("par_sep", &is_paragraph_separator); set_buffer_hook ("format_paragraph_hook", &format_paragraph_hook); set_buffer_hook ("wrap_hook", &wrap_hook); set_buffer_hook ("color_region_hook", &color_buffer); set_buffer_hook ("newline_indent_hook", &newline_indent_hook); %set_buffer_hook ("mark_paragraph_hook", &mark_paragraph); set_comment_info ("mailedit", ">", "", 0); run_mode_hooks ("mailedit_mode_hook"); }