Mutt: условный формат даты в «index_format»

15

У меня есть следующее значение для index_formatMutt:

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

который отображает дату в формате как

2013 Dec 5

Мне было интересно, возможно ли иметь разные форматы даты в зависимости от того, сколько лет электронной почте. Под этим я подразумеваю:

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

Я думаю, что видел эту функциональность в Thunderbird. Было бы неплохо иметь его в дураках

Мартин Вегтер
источник

Ответы:

16

Если вы используете "Mutt" версию разработки (v1.5 +) - и вам это обязательно нужно - есть возможность использовать внешний фильтр, как описано в руководстве .

Сначала вам нужен скрипт, который может выводить разные вещи в зависимости от возраста сообщения. Вот пример в 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))

Сохраните это как mutt-fmt-dateгде-нибудь на вашем пути.

Здесь важны две вещи:

  • Строка формата должна содержать одно вхождение, {}которое заменяется возвращаемым значением age_fmt()Python.
  • Строка формата должна заканчиваться символом %так, чтобы Mutt ее интерпретировал.

Тогда вы можете использовать его .muttrcследующим образом:

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

Матт будет тогда

  1. интерпретировать в %[%s]соответствии с правилами для строк формата.
  2. вызов mutt-fmt-dateс результатом 1. в качестве аргумента (потому что |в конце).
  3. интерпретировать то, что он возвращает из скрипта, как строку формата снова (из- %за конца).

Предостережение : скрипт будет выполняться для каждого сообщения, которое должно быть отображено. Получающаяся задержка может быть весьма заметна при прокрутке почтового ящика.

Вот версия на 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, *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;
}

Это идет вместе с строкой muttrc:

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

источник
У меня еще не было времени на отладку, но, похоже, есть проблема с этим решением и темами, которые содержат знак%. Патчи будут оценены!
1
Я создал щедрость. У вас есть идеи, как исправить ошибку?
Мартин Вегтер
7

К сожалению, это не представляется возможным в текущих версиях Mutt.

$index_formatподдерживает определенный набор спецификаторов формата, используя различные метаданные сообщения. Он описан в руководстве Mutt (или здесь приведена документация «стабильной» версии для того же самого ), и, как вы можете видеть из таблицы, существует только несколько спецификаторов формата, которые являются условными. Те %M, %yи %Y; % M - это количество скрытых сообщений, если поток свернут, а% y и% Y - это заголовки X-Label, если они есть.

Фактическое форматирование даты и времени сообщения выполняется strftime(3), который вообще не поддерживает условное форматирование.

Можно было бы сделать уродливый обходной путь, постоянно переписывая Date:заголовки файлов сообщений , но я бы не хотел этого делать по крайней мере. Тем не менее, это наименее плохая возможность, о которой я могу думать.

Единственное реальное решение, о котором я могу подумать, - это реализовать такую ​​поддержку в Mutt (что почти наверняка так и делает Thunderbird) или написать замену, strftimeкоторая поддерживает условное форматирование, и внедрить ее с помощью LD_PRELOAD или аналогичного механизма. Последнее, однако, повлияет на все отображение даты и времени в Mutt, которое проходит через strftime, а не только в отношении индекса сообщения.

CVn
источник
2
Если вы используете версию 1.5+ (что вам абсолютно необходимо), есть способ. Предлагать переписать заголовки даты просто
@hop FWIW, ваш ответ получил мое одобрение.
CVn
4

По какой-то причине более новые версии mutt (1.7 показали, что проблема) префикс строки даты с символами '14' и '32', которые мешают atoi преобразовать строку в int. Изменение строки на

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

Возможно, глупое решение, но оно работает для меня.

Маркус Н
источник
4

Немного отредактировал @Marcus 'c версию (но пока нет решения %этой проблемы):

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

Даты форматируются следующим образом (все время в 24-часовом формате):

  • 02:04 для сегодняшней почты
  • ydy 02:04 за вчерашнюю почту
  • Thu 02:04 за последние 7 дней
  • 27.Mar на почту текущего года
  • 13.12.16 за почту предыдущих лет

Полный индексный формат в этом примере #no [flags] #no_of_attachments date sender subject msg_size

Laur
источник
3

Внесены некоторые изменения, но проблема «% в теме» не решена

#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;
}
Маркус Н
источник
Было бы хорошо, если бы вы кратко изложили сделанные вами изменения и причины их возникновения.
Загримсан
0

Эта index_formatпеременная

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

вместе с этим изменением, mfdate.cпредставленным в этом ответе пользователем 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;
}

у меня работает правильно, mutt 1.6.1и, как видите, проблем со %знаком в теме нет, если реальная проблема была в следующем:введите описание изображения здесь

Это первоначальная «просто рабочая» версия, потому что после более внимательного изучения исходного вопроса я не уверен, что вы этого хотите. Однако, если это является то , что вы хотите , дайте мне знать , и мы будем думать , как сделать его лучше.

РЕДАКТИРОВАТЬ :

Он также может работать с вашими предпочтениями 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;
}

введите описание изображения здесь

РЕДАКТИРОВАТЬ :

Позвольте мне объяснить, как это работает:

The mfdateпринимает 2 аргумента:

"%[%s]"

и:

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

Первый аргумент только time of the message, как описано в index_formatдокументации в .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

В этом случае fmtзаменяется %s, потому что , как %sсредство , The number of seconds since the Epochкак объяснено man strftime. Первый аргумент используется для вычисления как старые сообщения и какие меток: old, recentили todayон должен иметь.

Второй аргумент - это оставшаяся часть index_format переменной. Он используется mfdateтолько для печати, но дополнительный %добавляется в конце, printfпотому что, как сказано в руководстве Mutt :

Возвращенная строка будет использоваться для отображения. Если возвращаемая строка оканчивается на%, она будет передана через средство форматирования во второй раз.

Здесь каждый %удваивается, потому что мы хотим передать литерал %во второе форматирование, выполненное с помощью mutt.

Аркадиуш Драбчик
источник
Почему отрицательный голос? Что-то не так с этим ответом?
Аркадиуш Драбчик