mutt: formato de fecha condicional en "index_format"


15

Tengo el siguiente valor establecido index_formaten mutt:

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

que muestra la fecha en el formato como

2013 Dec 5

Me preguntaba si es posible tener diferentes formatos de fecha dependiendo de la antigüedad del correo electrónico. Con eso quiero decir:

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

Creo que he visto esta funcionalidad en Thunderbird. Sería bueno tenerlo en mutt

Respuestas:


16

Si está utilizando la versión de "desarrollo" de mutt (v1.5 +), y debería hacerlo, existe la posibilidad de utilizar un filtro externo como se describe en el manual .

Primero necesita un script que pueda generar diferentes cosas según la antigüedad de un mensaje. Aquí hay un ejemplo 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))

Guarda esto como en mutt-fmt-datealgún lugar de tu RUTA.

Aquí hay dos cosas importantes:

  • La cadena de formato debe contener una ocurrencia de la {}cual se reemplaza con el valor de retorno de age_fmt()Python.
  • La cadena de formato tiene que terminar con un %para que Mutt la interprete.

Entonces puedes usarlo en tu .muttrccomo sigue:

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

Mutt entonces

  1. interpretar de %[%s]acuerdo con las reglas para cadenas de formato.
  2. llame mutt-fmt-datecon el resultado de 1. como argumento (debido |al final).
  3. interpreta de nuevo lo que obtiene del script como cadena de formato (debido %al final).

Advertencia : el script se ejecutará para cada mensaje que se va a mostrar. El retraso resultante puede ser bastante notable cuando se desplaza por un buzón.

Aquí hay una versión en C que funciona de manera algo adecuada:

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

Esto va junto con la línea muttrc:

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

Todavía no he tenido tiempo de depurar esto, pero parece haber un problema con esta solución y los temas que contienen un signo%. ¡Los parches serían apreciados!

1
He creado una recompensa. ¿Tienes alguna idea de cómo solucionar el error?
Martin Vegter

7

Desafortunadamente, eso no parece ser posible con las versiones actuales de Mutt.

$index_formatadmite un conjunto específico de especificadores de formato, que se basan en varios metadatos de mensajes. Se describe en el manual de Mutt (o aquí está la documentación de la versión "estable" para el mismo ), y como puede ver en la tabla, solo hay unos pocos especificadores de formato que son condicionales. Esos son %M, %yy %Y; % M es el número de mensajes ocultos si el hilo está colapsado, y% y y% Y son encabezados de etiqueta X si están presentes.

El formato real de la fecha y hora del mensaje se realiza mediante strftime(3), que no admite el formato condicional en absoluto.

Que podría ser posible hacer un feo solución reescribiendo continuamente los archivos de mensajes Date:cabeceras, pero no me gustaría hacer eso por lo menos. Sin embargo, es la posibilidad menos mala que se me ocurre.

La única solución real que se me ocurre sería implementar dicho soporte en Mutt (que casi seguro es cómo lo hace Thunderbird) o escribir un reemplazo strftimeque admita el formato condicional e inyectarlo usando LD_PRELOAD o un mecanismo similar. Sin embargo, esto último afectará toda la visualización de fecha y hora en Mutt que pase por el tiempo de ejecución, no solo en relación con el índice de mensajes.


2
Si está utilizando la versión 1.5+ (que absolutamente debería), hay una manera. Sin embargo

@hop FWIW, tu respuesta recibió mi voto positivo.
un CVn

4

Por alguna razón, las versiones más recientes de mutt (1.7 mostraron ese problema) prefieren la cadena de fecha con los caracteres '14' y '32', que evitan que atoi convierta la cadena a int. Cambiar la línea a

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

Posiblemente una solución estúpida, pero funciona para mí.


4

Se editó un poco la versión de @Marcus 'c (aunque todavía no hay solución para %el tema):

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

Este formatea las fechas de la siguiente manera (todos los horarios están en formato de 24 horas):

  • 02:04 para el correo de hoy
  • ydy 02:04 para el correo de ayer
  • Thu 02:04 por los últimos 7 días de correo
  • 27.Mar para el correo del año actual
  • 13.12.16 para el correo de años anteriores

El formato de índice completo en este ejemplo es #no [flags] #no_of_attachments date sender subject msg_size


3

Hizo algunas modificaciones, pero no resolvió el problema "% en el sujeto"

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

Sería bueno si resumiera los cambios que ha realizado y las razones detrás de ellos.
zagrimsan

0

Esta index_formatvariable

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

junto con esta modificación mfdate.cpresentada en esta respuesta por el usuario 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;
}

funciona correctamente para mí mutt 1.6.1y, como puede ver, no hay problemas con el %inicio de sesión en el tema, si de eso se trataba el problema real:ingrese la descripción de la imagen aquí

Esta es la versión inicial "simplemente funciona" porque después de analizar más de cerca su pregunta original , no estoy seguro de si esto es lo que desea. Sin embargo, si esto es lo que quieres, házmelo saber y pensaremos cómo mejorarlo.

EDITAR :

También puede funcionar con su preferido 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;
}

ingrese la descripción de la imagen aquí

EDITAR :

Déjame explicarte cómo funciona:

El mfdatetoma 2 argumentos:

"%[%s]"

y:

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

El primer argumento es solo time of the message, como se describe en la index_formatdocumentación en .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

En este caso fmtse reemplaza con %s, porque como %ssignifica The number of seconds since the Epochcomo se explica en man strftime. El primer argumento se utiliza para calcular la edad que el mensaje es y lo etiqueta: old, recento todayque debería tener.

El segundo argumento es la parte restante de la index_format variable. Se usa mfdatesolo para imprimir, pero %se agrega un extra al final printfporque, como dice en el manual de mutt :

La cadena devuelta se utilizará para mostrar. Si la cadena devuelta termina en%, se pasará por el formateador por segunda vez.

Cada %se duplica aquí porque queremos pasar un literal %al segundo formateo realizado por mutt.


¿Por qué el voto negativo? ¿Algo mal con esta respuesta?
Arkadiusz Drabczyk
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.