mutt: formato de data condicional em “index_format”

14

Eu tenho o seguinte valor definido para index_format em mutt:

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

que exibe a data no formato como

2013 Dec 5

Eu queria saber se é possível ter formatos de data diferentes dependendo da idade do email. Com isso quero dizer:

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

Acho que já vi essa funcionalidade no Thunderbird. Seria bom tê-lo em mutt

    
por Martin Vegter 05.12.2013 / 23:36

6 respostas

15

Se você estiver usando a versão "desenvolvimento" do mutt (v1.5 +) - e você absolutamente deveria - existe a possibilidade de usar um filtro externo como descrito no manual .

Primeiro, você precisa de um script que possa gerar resultados diferentes de acordo com a idade de uma mensagem. Aqui está um exemplo em 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))

Salve isso como mutt-fmt-date em algum lugar no seu PATH.

Duas coisas são importantes aqui:

  • A string de formato deve conter uma ocorrência de {} , que é substituído pelo valor de retorno de age_fmt() por Python.
  • A string de formatação deve terminar com % para que o Mutt a interprete.

Você pode usá-lo no seu .muttrc da seguinte forma:

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

Mutt então

  1. interprete %[%s] de acordo com as regras para as strings de formato.
  2. chame mutt-fmt-date com o resultado de 1. como argumento (por causa do | no final).
  3. interprete o que retorna do script como string de formato novamente (por causa do % no final).

Advertência : o script será executado para cada mensagem que será exibida. O atraso resultante pode ser bastante perceptível ao percorrer uma caixa de correio.

Aqui está uma versão em C que funciona de forma adequada:

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

Isso vai junto com a linha muttrc:

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

Infelizmente, isso não parece ser possível com as versões atuais do Mutt.

$index_format suporta um conjunto específico de especificadores de formato, desenhando a partir de vários metadados de mensagens. É descrito no manual do Mutt (ou aqui está a documentação da versão "estável" para o mesmo , e como você pode ver na tabela, há apenas alguns Especificadores de formato que são condicionais. Esses são %M , %y e %Y ; % M é o número de mensagens ocultas se o encadeamento estiver recolhido, e% y e% Y forem cabeçalhos X-Label se presentes.

A formatação real da data e hora da mensagem é feita por strftime(3) , que não suporta formatação de todo.

pode ser possível fazer uma solução feia , reescrevendo continuamente os arquivos de mensagens ' Date: headers, mas eu não gostaria de fazer isso, pelo menos. No entanto, é a menor possibilidade que eu possa imaginar.

A única solução real que consigo pensar seria implementar esse suporte no Mutt (que quase certamente é como o Thunderbird faz isso) ou escrever um substituto strftime que suporte a formatação condicional e injetar isso usando o LD_PRELOAD ou um similar mecanismo. Este último, no entanto, afetará a exibição de todas as datas e horas em Mutt que passa por strftime, não apenas relacionado ao índice de mensagens.

    
por 17.12.2013 / 14:23
4

Por alguma razão, versões mais recentes do mutt (1.7 mostraram esse problema) prefixam a cadeia de datas com os caracteres '14' e '32', que impedem que o atoi converta a string para um int. Alterando a linha para

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

Possivelmente uma solução estúpida, mas funciona para mim.

    
por 05.10.2016 / 12:02
4

Editado @Marcus 'c versão um pouco (ainda não há solução para o % no problema sujeito):

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

Estes formatos são os seguintes datas (todos os horários estão no formato 24h):

  • 02:04 para o e-mail de hoje
  • ydy 02:04 para o correio de ontem
  • Thu 02:04 nos últimos 7 dias de e-mail
  • 27.Mar para o correio do ano atual
  • 13.12.16 para o correio dos anos anteriores

O formato de índice completo neste exemplo é #no [flags] #no_of_attachments date sender subject msg_size

    
por 15.04.2017 / 02:35
3

Fiz algumas modificações, mas não resolvi o problema "% 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;
}
    
por 02.05.2016 / 10:32
-1

Esta variável index_format

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

junto com este mfdate.c modificado apresentado em esta resposta pelo usuário 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 corretamente para mim em mutt 1.6.1 e, como você pode ver, não há problemas com % no assunto, se é sobre o problema real:

Estaéaversãoinicial"justa de trabalho" porque depois de dar uma olhada mais de perto na sua pergunta original eu sou Não tenho certeza se é isso que você quer. No entanto, se isso é o que você quer, deixe-me saber e vamos pensar em como torná-lo melhor.

EDITAR :

Ele também pode funcionar com seu index_format preferido:

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

EDITAR:

Deixe-meexplicarcomofunciona:

Omfdaterecebe2argumentos:

"%[%s]"

e:

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

O primeiro argumento é apenas time of the message , conforme descrito em index_format documentação em .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

Nesse caso, fmt é substituído por %s , porque como %s significa The number of seconds since the Epoch , conforme explicado em man strftime . o primeiro argumento é usado para calcular a idade da mensagem e o que label: old , recent ou today que deveria ter.

O segundo argumento é a parte restante do index_format variável. Ele é usado em mfdate apenas para impressão, mas um % extra é adicionado no final de printf porque, como diz o manual do mutt :

The string returned will be used for display. If the returned string ends in %, it will be passed through the formatter a second time.

Todo % é dobrado aqui porque queremos passar um literal % para o segunda formatação feita por mutt .

    
por 04.05.2017 / 21:34

Tags