mutt: format de date conditionnel dans "index_format"

J'ai la valeur suivante pour index_format dans mutt:

 "%Z %{%Y %b %e %H:%M} %?X?(%X)& ? %-22.22F %.100s %> %5c " 

qui affiche la date sous le format

 2013 Dec 5 

Je me demandais s'il est possible d'avoir différents formats de date en fonction de l'âge de l'email. Par cela je veux dire:

 for less than 7 days: today, yesterday, tuesday, monday this year: Dec 5 older than this year: 2013 Dec 5 

Je pense que j'ai vu cette fonctionnalité dans Thunderbird. Serait bien de l'avoir à Mutt

Si vous utilisez la version "développement" de mutt (v1.5 +) – et vous devriez absolument – il est possible d'utiliser un filter externe comme décrit dans le manuel .

Vous avez d'abord besoin d'un script qui peut afficher différentes choses en fonction de l'âge d'un message. Voici un exemple en Python:

 #!/usr/bin/env python """mutt format date Prints different index_format ssortingngs for mutt according to a messages age. The single command line argument should be a unix timestamp giving the message's date (%{}, etc. in Mutt). """ import sys from datetime import datetime INDEX_FORMAT = "%Z {} %?X?(%X)& ? %-22.22F %.100s %> %5c%" def age_fmt(msg_date, now): # use iso date for messages of the previous year and before if msg_date.date().year < now.date().year: return '%[%Y-%m-%d]' # use "Month Day" for messages of this year if msg_date.date() < now.date(): return '%10[%b %e]' # if a message appears to come from the future if msg_date > now: return ' b0rken' # use only the time for messages that arrived today return '%10[%H:%m]' if __name__ == '__main__': msg_date = datetime.fromtimestamp(int(sys.argv[1])) now = datetime.now() print INDEX_FORMAT.format(age_fmt(msg_date, now)) 

Enregistrez ceci comme mutt-fmt-date quelque part sur votre PATH.

Deux choses sont importantes ici:

  • La string de format doit contenir une occurrence de {} qui est remplacée par la valeur de return de age_fmt() par Python.
  • La string de format doit se terminer par un % afin que Mutt l'interprète.

Ensuite, vous pouvez l'utiliser dans votre .muttrc comme suit:

 set index_format="mutt-fmt-date %[%s] |" 

Mutt va alors

  1. interpréter %[%s] selon les règles pour les strings de format.
  2. appelez mutt-fmt-date avec le résultat de 1. comme argument (à cause du | à la fin).
  3. interpréter ce qu'il reçoit du script en tant que string de format à nouveau (à cause du % à la fin).

Avertissement : le script sera exécuté pour chaque message qui doit être affiché. Le timeout qui en résulte peut être tout à fait perceptible lors du défilement d'une boîte aux lettres.

Voici une version en C qui fonctionne assez bien:

 #include <stdlib.h> #include <stdio.h> #include <time.h> #define DAY (time_t)86400 #define YEAR (time_t)31556926 int main(int argc, const char *argv[]) { time_t current_time; time_t message_time; const char *old, *recent, *today; const char *format; current_time = time(NULL); if (argc!=6) { printf("Usage: %s old recent today format timestamp\n", argv[0]); return 2; } old = argv[1]; recent = argv[2]; today = argv[3]; format = argv[4]; message_time = atoi(argv[5]); if ((message_time/YEAR) < (current_time/YEAR)) { printf(format, old); } else if ((message_time/DAY) < (current_time/DAY)) { printf(format, recent); } else { printf(format, today); } return 0; } 

Cela va de pair avec la ligne muttrc:

 set index_format='mfdate "%[%d.%m.%y]" "%8[%e. %b]" "%8[%H:%m]" "%Z %%s %-20.20L %?y?[%-5.5y]& ? %?M?+& ?%s%%" "%[%s]" |' 

Malheureusement, cela ne semble pas possible avec les versions actuelles de Mutt.

$index_format prend en charge un set spécifique de spécificateurs de format, en tirant parti de diverses métadonnées de message. Il est décrit dans le manuel Mutt (ou ici la documentation de la version "stable" ), et comme vous pouvez le voir sur la table, seuls quelques spécificateurs de format sont conditionnels. Ce sont %M , %y et %Y ; % M est le nombre de messages masqués si le thread est réduit, et% y et% Y sont des en-têtes X-Label si présents.

La mise en forme réelle de la date et de l'heure du message est effectuée par strftime(3) , qui ne prend pas en charge la mise en forme conditionnelle.

Il pourrait être possible de faire une solution de contournement en réécrivant continuellement les files Date: têtes, mais je ne voudrais pas le faire au less. Cependant, c'est la less mauvaise possibilité à laquelle je puisse penser.

La seule vraie solution que je puisse imaginer serait soit de mettre en place un tel support dans Mutt (ou presque), soit d'écrire un strftime rlocation strftime charge la mise en forme conditionnelle et l' strftime aide de LD_PRELOAD ou d'un mécanisme similaire. Ce dernier, cependant, affectera toute l' affichage de la date et de l'heure dans Mutt qui passe par strftime, non seulement en relation avec l'index du message.

Pour une raison quelconque, des versions plus récentes de mutt (1.7 ont montré ce problème) préfixent la string de date avec les caractères «14» et «32», qui empêchent atoi de convertir la string en int. Changer la ligne pour

 message_time = atoi(2+argv[7]); 

Peut-être une solution stupide, mais cela fonctionne pour moi.

Modifié la version c de @Marcus un peu (toujours pas de solution au % dans le problème sujet cependant):

 // -*- coding:utf-8-unix; mode:c; -*- /* Sets mutt index date based on mail age. build: gcc mutt-index-date-formatter.c -o mutt-index-format use this line in .muttrc: set index_format = 'mutt-index-format "%9[%d.%m.%y]" "%9[%e.%b]" "%8[%a %H:%m]" "%[%H:%m]" "%3C [%Z] %?X?%2X& -? %%s %-20.20L %?M?+%-2M& ? %s %> [%4c]asladfg" "%[%s]" |'*/ // //////////////////////////////////////////////////////////////// #include <stdlib.h> #include <stdio.h> #include <time.h> #define DAY (time_t)86400 #define WEEK (time_t)604800 #define YEAR (time_t)31556926 int main(int argc, const char *argv[]) { time_t current_time; time_t message_time; struct tm *ltime; unsigned int todays_seconds=0; unsigned int seconds_this_morning=0; const char *last_year, *this_year, *last_months, *last_week, *today; const char *format; char *concat_str; current_time = time(NULL); ltime = localtime(&current_time); todays_seconds = ltime->tm_hour*3600 + ltime->tm_min*60 + ltime->tm_sec; seconds_this_morning = current_time - todays_seconds; // unix time @ 00:00 if (argc != 7) { printf("Usage: %s last_year this_year last_week today format timestamp\n", argv[0]); return 2; } last_year = argv[1]; this_year = argv[2]; last_week = argv[3]; today = argv[4]; format = argv[5]; message_time = atoi(2 + argv[6]); if (message_time >= seconds_this_morning) { asprintf(&concat_str, " %s", today); printf(format, concat_str); } else if (message_time >= seconds_this_morning - DAY) { asprintf(&concat_str, "ydy %s", today); printf(format, concat_str); } else if (message_time > seconds_this_morning - WEEK) { printf(format, last_week); } else if (message_time/YEAR < current_time/YEAR) { printf(format, last_year); } else { printf(format, this_year); } return 0; } 

Ceci met en forme les dates suivantes (toutes les heures sont au format 24h):

  • 02:04 pour le courrier d'aujourd'hui
  • ydy 02:04 pour le courrier d'hier
  • Thu 02:04 pour les 7 derniers jours mail
  • 27.Mar pour le courrier de l'année en cours
  • 13.12.16 pour le courrier des années précédentes

Le format d'index complet dans cet exemple est #no [flags] #no_of_attachments date sender subject msg_size

A apporté quelques modifications mais n'a pas résolu le problème "% in subject"

 #include <stdlib.h> #include <stdio.h> #include <time.h> #define DAY (time_t)86400 #define WEEK (time_t)604800 #define MONTH (time_t)2678400 #define YEAR (time_t)31556926 /*I use this line in .muttrc: * set index_format = '/home/marcus/.mutt/mfdate "%9[%d.%m.%y]" "%9[%e.%b]" " [%6[%e.%b]]" "%8[%a %H:%m]" " %[%H:%m]" "%Z %%s %?X?%2X& ? %-20.20L %?M?+%-2M& ? %.86s %> [%4c]asladfg" "%[%s]" |'*/ int main(int argc, const char *argv[]) { time_t current_time; time_t message_time; struct tm *ltime; unsigned int todays_seconds=0; unsigned int seconds_this_morning=0; const char *last_year, *this_year, *last_months, *last_week, *today; const char *format; current_time = time(NULL); ltime = localtime(&current_time); todays_seconds = ltime->tm_hour*3600 + ltime->tm_min*60 + ltime->tm_sec; seconds_this_morning = current_time - todays_seconds; if (argc!=8) { printf("Usage: %s last_year this_year today format timestamp\n", argv[0]); return 2; } last_year = argv[1]; this_year = argv[2]; last_months = argv[3]; last_week = argv[4]; today = argv[5]; format = argv[6]; message_time = atoi(argv[7]); /* *if ((message_time+YEAR) < current_time) { * printf(format, last_year); *} else if ((message_time+MONTH) < current_time) { * printf(format, this_year); *} else if ((message_time+WEEK) < current_time) { * printf(format, last_months); *} else if ((message_time+DAY) < current_time) { * printf(format, last_week); *} else { * printf(format, today); *} */ if ((message_time/YEAR) < (current_time/YEAR)) { printf(format, last_year); } else if ((message_time/MONTH) < (current_time/MONTH)) { printf(format, this_year); } else if ((message_time + WEEK) < current_time) { /*} else if ((message_time/DAY) < (current_time/DAY)) {*/ printf(format, last_months); /* *} else if ((message_time+DAY) < current_time) { * printf(format, last_week); */ } else if ((message_time ) < seconds_this_morning) { printf(format, last_week); } else { printf(format, today); } return 0; } 

Cette variable index_format

 set index_format='mfdate "%[%s]" "%4C %Z %[!%b %d %Y] %-17.17F (%3l) %s" |' 

avec cette modification mfdate.c présenté dans cette réponse par l'user hop :

 #include <stdlib.h> #include <stdio.h> #include <time.h> #define DAY (time_t)86400 #define YEAR (time_t)31556926 int main(int argc, const char *argv[]) { time_t current_time; time_t message_time; const char *old = "old"; char *recent = "recent"; char *today = "today"; const char *format; current_time = time(NULL); if (argc != 3) { printf("Usage: %s format\n", argv[0]); return EXIT_FAILURE; } format = argv[2]; message_time = atoi(argv[1]); if ((message_time/YEAR) < (current_time/YEAR)) { printf("%s,%s", old, format); } else if ((message_time/DAY) < (current_time/DAY)) { printf("%s,%s", recent, format); } else { printf("%s,%s", today, format); } return EXIT_SUCCESS; } 

fonctionne correctement pour moi dans mutt 1.6.1 et comme vous voyez, il n'y a pas de problème avec % signe dans le sujet, si tel est le problème réel: entrer la description de l'image ici

Ceci est la version initiale "juste de travail" parce qu'après avoir regardé de plus près votre question initiale je ne suis pas sûr si c'est ce que vous voulez. Cependant, si c'est ce que vous voulez faites le moi savoir et nous penserons comment le rendre meilleur.

EDIT :

Il peut également fonctionner avec votre index_format préféré:

 set index_format='mfdate "%[%s]" "%%Z %%{%%Y %%b %%e %%H:%%M} %%?X?(%%X)& ? %%-22.22F %%.100s %%> %%5c" |' 

mfdate.c:

 #include <stdlib.h> #include <stdio.h> #include <time.h> #define DAY (time_t)86400 #define YEAR (time_t)31556926 int main(int argc, const char *argv[]) { time_t current_time; time_t message_time; const char *old = "old"; char *recent = "recent"; char *today = "today"; const char *format; current_time = time(NULL); if (argc != 3) { printf("Usage: %s format\n", argv[0]); return EXIT_FAILURE; } format = argv[2]; message_time = atoi(argv[1]); if ((message_time/YEAR) < (current_time/YEAR)) { printf("%s,%s%%", old, format); } else if ((message_time/DAY) < (current_time/DAY)) { printf("%s,%s%%", recent, format); } else { printf("%s,%s%%", today, format); } return 0; } 

entrer la description de l'image ici

EDIT :

Laissez-moi vous expliquer comment cela fonctionne:

Le mfdate prend 2 arguments:

 "%[%s]" 

et:

 "%%Z %%{%%Y %%b %%e %%H:%%M} %%?X?(%%X)& ? %%-22.22F %%.100s %%> %%5c" 

Le premier argument est uniquement l' time of the message , comme décrit dans la documentation .muttrc dans .muttrc :

 # %[fmt] the date and time of the message is converted to the local # time zone, and ``fmt'' is expanded by the library function # ``strftime''; a leading bang disables locales 

Dans ce cas, fmt est remplacé par %s , parce que %s signifie The number of seconds since the Epoch man strftime The number of seconds since the Epoch comme expliqué dans le man strftime . Le premier argument est utilisé pour calculer l'âge du message et quel label: old , recent ou today il devrait avoir.

Le second argument est la partie restante de la variable index_format . Il est utilisé dans mfdate uniquement pour l'printing mais un % supplémentaire est ajouté à la fin de printf car comme il est dit dans le manuel de Mutt :

La string renvoyée sera utilisée pour l'affichage. Si la string renvoyée se termine en%, elle sera transmise à travers le formateur une deuxième fois.

Chaque % est doublé ici parce que nous voulons passer un % littéral à la deuxième mise en forme faite par mutt .