mutt: format de date conditionnel dans "index_format"

15

J'ai la valeur suivante définie pour index_formatdans mutt:

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

qui affiche la date au format

2013 Dec 5

Je me demandais s'il était possible d'avoir différents formats de date en fonction de l'âge de l'e-mail. J'entends par là:

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

Je pense avoir vu cette fonctionnalité dans Thunderbird. Ce serait bien de l'avoir dans mutt

Martin Vegter
la source

Réponses:

16

Si vous utilisez la version "développement" de mutt (v1.5 +) - et vous devez absolument - il y a la possibilité d'utiliser un filtre externe comme décrit dans le manuel .

Vous avez d'abord besoin d'un script qui peut produire 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 strings 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-le mutt-fmt-datequelque part sur votre CHEMIN.

Deux choses sont importantes ici:

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

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

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

Mutt va alors

  1. interpréter %[%s]selon les règles des chaînes de format.
  2. appeler mutt-fmt-dateavec le résultat de 1. comme argument (à cause de |la fin).
  3. interpréter à nouveau ce qu'il récupère du script en tant que chaîne de formatage (à cause de %la fin).

Attention : le script sera exécuté pour chaque message qui va être affiché. Le retard résultant peut être tout à fait notable 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]" |'

la source
Je n'ai pas encore eu le temps de déboguer cela, mais il semble y avoir un problème avec cette solution et les sujets qui contiennent un signe%. Des correctifs seraient appréciés!
1
J'ai créé une prime. Avez-vous des idées pour corriger le bogue?
Martin Vegter
7

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

$index_formatprend en charge un ensemble spécifique de spécificateurs de format, à partir de diverses métadonnées de message. Il est décrit dans le manuel de Mutt (ou voici la documentation de la version "stable" pour le même ), et comme vous pouvez le voir dans le tableau, il n'y a que quelques spécificateurs de format conditionnels. Ce sont %M, %yet %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 s'ils sont 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 du tout en charge la mise en forme conditionnelle.

Il pourrait être possible de faire une solution de contournement laide en réécrivant continuellement les en- Date:têtes des fichiers de messages , mais je ne voudrais pas faire cela au moins. Cependant, c'est la moins mauvaise possibilité à laquelle je puisse penser.

La seule vraie solution à laquelle je peux penser serait d'implémenter un tel support dans Mutt (qui est presque certainement la façon dont Thunderbird le fait), ou d'écrire un remplacement strftimequi prend en charge le formatage conditionnel et d'injecter cela en utilisant LD_PRELOAD ou un mécanisme similaire. Ce dernier, cependant, affectera tous les affichages de date et d'heure dans Mutt qui passent par strftime, non seulement concernant l'index des messages.

un CVn
la source
2
Si vous utilisez la version 1.5+ (que vous devez absolument utiliser), il existe un moyen. Il est hilarant de
@hop FWIW, votre réponse a obtenu mon vote positif.
un CVn
4

Pour une raison quelconque, les versions plus récentes de mutt (1.7 ont montré ce problème) préfixent la chaîne de date avec les caractères '14' et '32', ce qui empêche atoi de convertir la chaîne en entier. Changer la ligne en

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

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

Marcus H
la source
4

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

// -*- 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;
}

Ce format date comme suit (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 de courrier
  • 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

laur
la source
3

Apporté quelques modifications, mais n'a pas résolu le problème "% dans le sujet"

#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;
}
Marcus H
la source
Il serait bon que vous résumiez les changements que vous avez apportés et les raisons qui les sous-tendent.
zagrimsan
0

Cette index_formatvariable

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

avec cette modification mfdate.cprésentée dans cette réponse par l'utilisateur 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 mutt 1.6.1et comme vous le voyez, il n'y a pas de problème de %connexion dans le sujet, si c'est le vrai problème:entrez la description de l'image ici

Il s'agit de la version initiale "qui fonctionne" car après avoir examiné de plus près votre question d' origine, je ne sais pas si c'est ce que vous voulez. Cependant, si c'est ce que vous voulez, faites le moi savoir et nous réfléchirons à la façon de l'améliorer.

MODIFIER :

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

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;
}

entrez la description de l'image ici

MODIFIER :

Permettez-moi d'expliquer comment cela fonctionne:

Le mfdateprend 2 arguments:

"%[%s]"

et:

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

Le premier argument est uniquement time of the message, comme décrit dans la index_formatdocumentation 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, fmtest remplacé par %s, car comme %smoyen The number of seconds since the Epochcomme expliqué dans man strftime. Le premier argument est utilisé pour calculer l'âge du message est et ce que l' étiquette: old, recentou todayil devrait avoir.

Le deuxième argument est la partie restante de la index_format variable. Il est utilisé mfdateuniquement pour l'impression, mais un supplément %est ajouté à la fin printfcar, comme il est indiqué dans le manuel mutt :

La chaîne retournée sera utilisée pour l'affichage. Si la chaîne retournée se termine par%, elle sera passée par le formateur une seconde fois.

Tout %est doublé ici parce que nous voulons passer un littéral %au deuxième formatage effectué par mutt.

Arkadiusz Drabczyk
la source
Pourquoi le downvote? Quelque chose ne va pas avec cette réponse?
Arkadiusz Drabczyk