mutt:「index_format」の条件付き日付形式


14

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-datePATHのどこかに保存します。

ここでは2つのことが重要です。

  • フォーマット文字列には、Pythonの{}戻り値で置き換えられる1つの出現が含まれている必要がありますage_fmt()
  • %Muttがフォーマット文字列を解釈できるように、フォーマット文字列はで終わる必要があります。

次に.muttrc、次のように使用できます。

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

Muttはその後

  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または同様のメカニズムを使用してそれを注入する置換を書くことです。ただし、後者は、メッセージインデックスに関連するだけでなく、strftimeを通過するMuttのすべての日付と時刻の表示に影響ます。


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


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提示されたこの修正とともに:

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

ここに画像の説明を入力してください

編集

それがどのように機能するかを説明しましょう:

mfdate2つの引数を取ります。

"%[%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。最初の引数は、どのように古いメッセージがあり、どのようなラベルを計算するために使用されていますoldrecentまたはtodayそれが持っている必要があります。

2番目の引数は、index_format 変数の残りの部分です。これmfdateは印刷のみに使用されますが、muttマニュアルに記載されているように%、最後に追加が追加されますprintf

返される文字列は表示に使用されます。返された文字列が%で終わる場合、フォーマッタを再度通過します。

によって行われる2番目のフォーマットに%リテラル%を渡したいため、ここではすべてが2倍になりますmutt


なぜ下票なのか?この答えに問題はありますか?
アルカディウスドラブチク
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.