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десь на вашій PATH.

Тут важливі дві речі:

  • Рядок формату повинен містити один параметр, {}який замінюється на повернене значення age_fmt()Python.
  • Рядок формату повинен закінчуватися %так, що Mutt інтерпретуватиме його.

Тоді ви можете використовувати його в .muttrcнаступному:

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

Mutt буде тоді

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

Caveat : сценарій буде виконуватися для кожного повідомлення, яке має бути відображене. Отримані затримки можуть бути досить помітними при прокручуванні поштової скриньки.

Ось версія в 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, який проходить через стрімкінг, не лише стосуючись індексу повідомлень.


2
Якщо ви використовуєте версію 1.5+ (яку ви абсолютно повинні), є спосіб. Запропонувати переписати заголовки дат весело, хоча…

@hop FWIW, ваша відповідь отримала мою позицію.
CVn

4

Чомусь новіші версії mutt (1.7 показали цю проблему) мають префікс рядка дати з символами "14" та "32", які не дозволяють перетворити рядок у int. Зміна лінії на

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

Можливо, дурне рішення, але воно працює на мене.


4

Трохи відредаговано версію @Marcus (все ще немає вирішення проблеми %в темі):

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


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

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

Редагувати :

Дозвольте пояснити, як це працює:

Триває mfdateаргументи:

"%[%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.


Чому потік? Щось не так у цій відповіді?
Аркадіуш Драбчик
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.