| # SPDX-License-Identifier: GPL-2.0 | |
| import os | |
| import subprocess | |
| import tempfile | |
| import _hkml | |
| import _hkml_fmtstr | |
| import _hkml_list_cache | |
| import _hkml_subproc | |
| import hkml_view | |
| import hkml_view_text | |
| def decorate_last_reference(text): | |
| lines = text.split('\n') | |
| if not lines[0].startswith('# last reference: '): | |
| return text | |
| fields = lines[0].split() | |
| if len(fields) != 4: | |
| return text | |
| last_reference_idx = int(lines[0].split()[3]) | |
| for idx, line in enumerate(lines): | |
| fields = line.split() | |
| if len(fields) == 0: | |
| continue | |
| if not fields[0].startswith('[') or not fields[0].endswith(']'): | |
| continue | |
| try: | |
| mail_idx = int(fields[0][1:-1]) | |
| except: | |
| continue | |
| if mail_idx != last_reference_idx: | |
| continue | |
| line = u'\u001b[32m' + line + u'\u001b[0m' | |
| line = '\x1B[3m' + line + '\x1B[0m' | |
| del lines[idx] | |
| lines.insert(idx, line) | |
| text = '\n'.join(lines) | |
| return text | |
| def pr_with_pager_if_needed(text): | |
| text = decorate_last_reference(text) | |
| try: | |
| if text.count('\n') < (os.get_terminal_size().lines * 9 / 10): | |
| print(text) | |
| return | |
| except OSError: | |
| # maybe the user is using pipe to the output | |
| pass | |
| fd, tmp_path = tempfile.mkstemp(prefix='hkml_open-') | |
| with open(tmp_path, 'w') as f: | |
| f.write(text) | |
| subprocess.call(['less', '-R', '-M', '--no-init', tmp_path]) | |
| os.remove(tmp_path) | |
| def mail_display_str(mail, head_columns=None, valid_mbox=False, | |
| for_draft_continue=False, recipients_per_line=False): | |
| lines = [] | |
| if valid_mbox is True: | |
| lines.append('From hackermail Thu Jan 1 00:00:00 1970') | |
| if for_draft_continue is True: | |
| head_fields = ['From', 'To', 'Cc', 'In-Reply-To'] | |
| else: | |
| head_fields = ['From', 'To', 'Cc', 'Message-Id', | |
| 'In-Reply-To', 'Date'] | |
| if valid_mbox is False and for_draft_continue is False: | |
| head_fields.append('Local-Date') | |
| head_fields.append('Subject') | |
| for head in head_fields: | |
| value = mail.get_field(head) | |
| if value: | |
| if head in ['To', 'Cc'] and recipients_per_line is True: | |
| recipients = value.split(',') | |
| for recipient in recipients: | |
| lines.append('%s: %s' % (head, recipient.strip())) | |
| continue | |
| if head_columns is not None: | |
| lines += _hkml_fmtstr.wrap_line('%s:' % head, value, head_columns) | |
| else: | |
| lines.append('%s: %s' % (head, value)) | |
| lines.append('\n%s' % mail.get_body()) | |
| return '\n'.join(lines) | |
| def last_open_mail_idx(): | |
| with open(os.path.join(_hkml.get_hkml_dir(), 'last_open_idx'), 'r') as f: | |
| return int(f.read()) | |
| def show_text(text, to_stdout, use_less, string_after_less, data=None): | |
| if to_stdout: | |
| print(text) | |
| return | |
| if use_less: | |
| pr_with_pager_if_needed(text) | |
| if string_after_less is not None: | |
| print(string_after_less) | |
| else: | |
| # todo: set text_view_data for type(data) is _hkml.Mail case | |
| hkml_view.view(draw_fn=hkml_view_text.show_text_viewer, | |
| fn_args=hkml_view_text.ShowTextViewerArgs( | |
| text_lines = text.split('\n'))) | |
| def show_git_commit(commit, to_stdout, use_less, string_after_less): | |
| try: | |
| show_text(subprocess.check_output(['git', 'show', commit]).decode(), | |
| to_stdout, use_less, string_after_less, data=None) | |
| return None | |
| except: | |
| return 'git show failed' | |
| def handle_command_target(args): | |
| cmd = args.target.split()[0] | |
| is_cmd = _hkml_subproc.cmd_available(cmd) | |
| if not is_cmd: | |
| return False | |
| try: | |
| output = subprocess.check_output(args.target, shell=True).decode() | |
| except: | |
| print('failed running the target command') | |
| return False | |
| show_text(output, args.stdout, args.use_less, None, data=None) | |
| return True | |
| def main(args): | |
| if handle_command_target(args): | |
| return | |
| if os.path.isfile(args.target): | |
| with open(args.target, 'r') as f: | |
| return show_text(f.read(), args.stdout, args.use_less, None, | |
| data=None) | |
| if not args.target.isdigit(): | |
| return show_git_commit(args.target, args.stdout, args.use_less, None) | |
| noti_current_index = True | |
| if args.target == 'prev': | |
| args.target = last_open_mail_idx() - 1 | |
| elif args.target == 'next': | |
| args.target = last_open_mail_idx() + 1 | |
| else: | |
| noti_current_index = False | |
| args.target = int(args.target) | |
| mail = _hkml_list_cache.get_mail(args.target) | |
| if mail is None: | |
| print('mail is not cached. Try older list') | |
| mail = _hkml_list_cache.get_mail(args.target, not_thread_idx=True) | |
| if mail is None: | |
| print('even not an older list index. Maybe git commit?') | |
| error = show_git_commit('%s' % args.target, args.stdout, | |
| args.use_less, None) | |
| if error is not None: | |
| print('cannot handle the request: %s' % error) | |
| exit(1) | |
| with open(os.path.join(_hkml.get_hkml_dir(), 'last_open_idx'), 'w') as f: | |
| f.write('%d' % args.target) | |
| try: | |
| head_columns = int(os.get_terminal_size().columns * 9 / 10) | |
| except: | |
| # maybe user is pipe-ing the output | |
| head_columns = None | |
| mail_str = mail_display_str(mail, head_columns) | |
| string_after_less = None | |
| if args.use_less and noti_current_index: | |
| string_after_less = '# you were reading %d-th index' % args.target | |
| show_text(mail_str, args.stdout, args.use_less, string_after_less, | |
| data=mail) | |
| def set_argparser(parser): | |
| parser.description = 'open a mail' | |
| parser.add_argument( | |
| 'target', metavar='<target>', | |
| help=' '.join( | |
| [ | |
| 'Target to open. Following types are supported.', | |
| '1. Index of a mail from the last open mails list/thread.', | |
| '2. \'next\': last open mail index plus one.', | |
| '3. \'prev\': last open mail index minus one.', | |
| '4. text file', | |
| '5. Git commit', | |
| '6. command.', | |
| ])) | |
| parser.add_argument( | |
| '--stdout', action='store_true', help='print without a pager') | |
| parser.add_argument( | |
| '--use_less', action='store_true', | |
| help='use less instead of hkml viewer') |