<commit_before>import datetime
import re
import time

import mailpile.plugins
from mailpile.commands import Command
from mailpile.mailutils import Email, ExtractEmails
from mailpile.search import MailIndex
from mailpile.util import *


def _friendly_date(days_ago, default):
  if days_ago < 1:
    return 'today'
  elif days_ago < 2:
    return 'yesterday'
  elif days_ago < 7:
    return '%d days ago' % days_ago
  else:
    return default

class SearchResults(dict):
  def _explain_msg_summary(self, info):
    days_ago = (time.time() - long(info[4], 36)) / (24*3600)
    msg_ts = long(info[4], 36)
    msg_date = datetime.date.fromtimestamp(msg_ts)
    date = '%4.4d-%2.2d-%2.2d' % (msg_date.year, msg_date.month, msg_date.day)
    expl = {
      'idx': info[0],
      'id': info[1],
      'from': info[2],
      'subject': info[3],
      'timestamp': msg_ts,
      'date': date,
      'friendly_date': _friendly_date(days_ago, date),
      'tag_ids': info[5],
      'url': '/=%s/%s/' % (info[0], info[1]),
    }
    if info[6]:
      expl['is_editable'] = True
    return expl

  def _prune_msg_tree(self, tree, context=True, parts=False, editable=False):
    pruned = {}
    prune = ['headers_lc', 'summary', 'tags', 'conversation', 'attachments']
    if not editable:
      prune.append('editing_string')
    for k in tree:
      if k not in prune:
        pruned[k] = tree[k]
    pruned['tag_ids'] = tree['tags']
    pruned['summary'] = self._explain_msg_summary(tree['summary'])
    if context:
      pruned['conversation'] = [self._explain_msg_summary(c)
                                for c in tree['conversation']]
    pruned['attachments'] = attachments = []
    for a in tree.get('attachments', []):
      att = {}
      att.update(a)
      if not parts:
        del att['part']
      attachments.append(att)
    return pruned

  def _message_details(self, emails, context=True):
    results = []
    for email in emails:
      tree = email.get_message_tree()
      email.evaluate_pgp(tree, decrypt=True)
      results.append(self._prune_msg_tree(tree, context=context))
    return results

  def _name(self, sender):
    words = re.sub('["<>]', '', sender).split()
    nomail = [w for w in words if not '@' in w]
    if nomail: return ' '.join(nomail)
    return ' '.join(words)

  def _names(self, senders):
    try:
      if len(senders) > 1:
        text = re.sub('["<>]', '', ', '.join([x.split()[0] for x in senders]))
        return text
    except IndexError:
      pass
    text = ', '.join([self._name(s) for s in senders])
    return re.sub(', (, )+', '..', text)

  def _compact(self, namelist, maxlen):
    l = len(namelist)
    while l > maxlen:
      namelist = re.sub(', *[^, \.]+, *', ',,', namelist, 1)
      if l == len(namelist): break
      l = len(namelist)
    namelist = re.sub(',,,+, *', ' .. ', namelist, 1)
    return namelist

  def __init__(self, session, idx,
               results=None, start=0, end=None, num=None, expand=None):<commit_msg>Shorten e-mail addresses (github issue #172), clarified name formatting code<commit_after>import datetime
import re
import time

import mailpile.plugins
from mailpile.commands import Command
from mailpile.mailutils import Email, ExtractEmails
from mailpile.search import MailIndex
from mailpile.util import *


def _friendly_date(days_ago, default):
  if days_ago < 1:
    return 'today'
  elif days_ago < 2:
    return 'yesterday'
  elif days_ago < 7:
    return '%d days ago' % days_ago
  else:
    return default

class SearchResults(dict):
  def _explain_msg_summary(self, info):
    days_ago = (time.time() - long(info[4], 36)) / (24*3600)
    msg_ts = long(info[4], 36)
    msg_date = datetime.date.fromtimestamp(msg_ts)
    date = '%4.4d-%2.2d-%2.2d' % (msg_date.year, msg_date.month, msg_date.day)
    expl = {
      'idx': info[0],
      'id': info[1],
      'from': info[2],
      'subject': info[3],
      'timestamp': msg_ts,
      'date': date,
      'friendly_date': _friendly_date(days_ago, date),
      'tag_ids': info[5],
      'url': '/=%s/%s/' % (info[0], info[1]),
    }
    if info[6]:
      expl['is_editable'] = True
    return expl

  def _prune_msg_tree(self, tree, context=True, parts=False, editable=False):
    pruned = {}
    prune = ['headers_lc', 'summary', 'tags', 'conversation', 'attachments']
    if not editable:
      prune.append('editing_string')
    for k in tree:
      if k not in prune:
        pruned[k] = tree[k]
    pruned['tag_ids'] = tree['tags']
    pruned['summary'] = self._explain_msg_summary(tree['summary'])
    if context:
      pruned['conversation'] = [self._explain_msg_summary(c)
                                for c in tree['conversation']]
    pruned['attachments'] = attachments = []
    for a in tree.get('attachments', []):
      att = {}
      att.update(a)
      if not parts:
        del att['part']
      attachments.append(att)
    return pruned

  def _message_details(self, emails, context=True):
    results = []
    for email in emails:
      tree = email.get_message_tree()
      email.evaluate_pgp(tree, decrypt=True)
      results.append(self._prune_msg_tree(tree, context=context))
    return results

  def _name(self, sender, short=True):
    words = re.sub('["<>]', '', sender).split()
    nomail = [w for w in words if not '@' in w]
    if nomail:
      if short:
        return nomail[0]
      return ' '.join(nomail)
    elif words:
      if short:
        return words[0].split('@', 1)[0]
      return words[0]
    return '(nobody)'

  def _names(self, senders):
    if len(senders) > 1:
      return ', '.join([self._name(x) for x in senders])
    if len(senders) < 1:
      return '(no sender)'
    if senders:
      return self._name(senders[0], short=False)
    return ''

  def _compact(self, namelist, maxlen):
    l = len(namelist)
    while l > maxlen:
      namelist = re.sub(', *[^, \.]+, *', ',,', namelist, 1)
      if l == len(namelist): break
      l = len(namelist)
    namelist = re.sub(',,,+, *', ' .. ', namelist, 1)
    return namelist

  def __init__(self, session, idx,
               results=None, start=0, end=None, num=None, expand=None):
{'fraction_non_alphanumeric': 0.15438539289207695, 'fraction_numerical': 0.012552983371372678, 'mean_word_length': 2.8633501259445846, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 10, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5494385', 'n_tokens_mistral': 2204, 'n_tokens_neox': 2100, 'n_words': 524}