Source code for now.thirdparty.PyInquirer.prompts.editor

# -*- coding: utf-8 -*-
"""
`editor` type question
"""
import inspect
import os
import sys

from prompt_toolkit.lexers import SimpleLexer
from prompt_toolkit.shortcuts import PromptSession
from prompt_toolkit.validation import Validator, ValidationError


from .common import default_style

# use std prompt-toolkit control

WIN = sys.platform.startswith('win')


[docs]class EditorArgumentsError(Exception): pass
[docs]class Editor: def __init__(self, editor=None, env=None, require_save=True, extension='.txt'): self.editor = editor self.env = env self.require_save = require_save self.extension = extension
[docs] def get_editor(self): if self.editor is not None and self.editor.lower() != "default": return self.editor for key in 'VISUAL', 'EDITOR': rv = os.environ.get(key) if rv: return rv if WIN: return 'notepad' for editor in 'vim', 'nano': if os.system('which %s >/dev/null 2>&1' % editor) == 0: return editor return 'vi'
[docs] def edit_file(self, filename): import subprocess editor = self.get_editor() if self.env: environ = os.environ.copy() environ.update(self.env) else: environ = None try: c = subprocess.Popen( '%s "%s"' % (editor, filename), env=environ, shell=True ) exit_code = c.wait() if exit_code != 0: raise Exception('%s: Editing failed!' % editor) except OSError as e: raise Exception('%s: Editing failed: %s' % (editor, e))
[docs] def edit(self, text): import tempfile text = text or '' if text and not text.endswith('\n'): text += '\n' fd, name = tempfile.mkstemp(prefix='editor-', suffix=self.extension) try: if WIN: encoding = 'utf-8-sig' text = text.replace('\n', '\r\n') else: encoding = 'utf-8' text = text.encode(encoding) f = os.fdopen(fd, 'wb') f.write(text) f.close() timestamp = os.path.getmtime(name) self.edit_file(name) if self.require_save and os.path.getmtime(name) == timestamp: return None f = open(name, 'rb') try: rv = f.read() finally: f.close() return rv.decode('utf-8-sig').replace('\r\n', '\n') finally: os.unlink(name)
[docs]def edit( text=None, editor=None, env=None, require_save=True, extension='.txt', filename=None ): r"""Edits the given text in the defined editor. If an editor is given (should be the full path to the executable but the regular operating system search path is used for finding the executable) it overrides the detected editor. Optionally, some environment variables can be used. If the editor is closed without changes, `None` is returned. In case a file is edited directly the return value is always `None` and `require_save` and `extension` are ignored. If the editor cannot be opened a :exc:`UsageError` is raised. Note for Windows: to simplify cross-platform usage, the newlines are automatically converted from POSIX to Windows and vice versa. As such, the message here will have ``\n`` as newline markers. :param text: the text to edit. :param editor: optionally the editor to use. Defaults to automatic detection. :param env: environment variables to forward to the editor. :param require_save: if this is true, then not saving in the editor will make the return value become `None`. :param extension: the extension to tell the editor about. This defaults to `.txt` but changing this might change syntax highlighting. :param filename: if provided it will edit this file instead of the provided text contents. It will not use a temporary file as an indirection in that case. """ editor = Editor( editor=editor, env=env, require_save=require_save, extension=extension ) if filename is None: return editor.edit(text) editor.edit_file(filename)
[docs]def question(message, **kwargs): default = kwargs.pop('default', '') eargs = kwargs.pop('eargs', {}) validate_prompt = kwargs.pop('validate', None) if validate_prompt: if inspect.isclass(validate_prompt) and issubclass(validate_prompt, Validator): kwargs['validator'] = validate_prompt() elif callable(validate_prompt): class _InputValidator(Validator): def validate(self, document): verdict = validate_prompt(document.text) if not verdict == True: if verdict == False: verdict = 'invalid input' raise ValidationError( message=verdict, cursor_position=len(document.text) ) kwargs['validator'] = _InputValidator() for k, v in eargs.items(): if v == "" or v == " ": raise EditorArgumentsError("Args '{}' value should not be empty".format(k)) editor = eargs.get("editor", None) ext = eargs.get("ext", ".txt") env = eargs.get("env", None) text = default filename = eargs.get("filename", None) multiline = True if not editor else False save = eargs.get("save", None) if editor: _text = edit( editor=editor, extension=ext, text=text, env=env, filename=filename, require_save=save, ) if filename: default = filename else: default = _text # TODO style defaults on detail level kwargs['style'] = kwargs.pop('style', default_style) qmark = kwargs.pop('qmark', '?') def _get_prompt_tokens(): return [('class:questionmark', qmark), ('class:question', ' %s ' % message)] return PromptSession( message=_get_prompt_tokens, lexer=SimpleLexer('class:answer'), multiline=multiline, enable_open_in_editor=True, vi_mode=True, **kwargs )