interactive.py 3.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
# -*- coding: utf-8 -*-
#
# interactive.py
# --------------
#
# Copyright (C) 2007 Jeremie Dimino <jeremie@dimino.org>
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This file is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.

'''Utilitaire pour poser des questions de manières interactives
à l'utilisateur, à la manière de darcs.'''

import os, sys, tty, termios
from affich_tools import cprint

__all__ = ["getch", "ask", "Exit"]

def getch():
    fd = sys.stdin.fileno()
32 33 34 35
    try:
        mode = termios.tcgetattr(fd)
    except:
        return os.read(fd, 1)
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
    try:
        tty.setraw(fd)
        return os.read(fd, 1)
    finally:
        termios.tcsetattr(fd, termios.TCSAFLUSH, mode)

# Constantes de choix
Exit = ("q", "quitter le programme", None, lambda: sys.exit(0))

def ask(message, choices):
    '''Pose une question à l'utilisateur.
choices est une liste d'élément de la forme (choix) ou (choix, doc)
ou (choix, doc, valeur) ou encore (choix, doc, valeur, operation), où:
- choix sont les  lettres pour le choix, si une est en majuscule alors
  ce choix est celui par défaut.
- doc est une description du choix
- valeur est la valeur renvoyée si ce choix est fait, par défaut c'est choix[0].lower()
- operation est soit une fonction, auquel cas elle est éxécutée si le choix est fait
  (et le questionnement continue si elle renoie vrai),
  soit un tuple sur lequel ask est éxécutée,
  soit une chaîne qui est affichée'''
    while True:
        cprint("%s [%s], ou ? pour l'aide: " % (message, "".join([c[0] for c in choices])), "bleu", newline=False)
        sys.stdout.flush()
        answer = getch()
        sys.stdout.write(answer+"\n")
        if answer in ['\x03', '\x04']:
            raise KeyboardInterrupt()
        if answer == " ":
            for choice in choices:
Jeremie Dimino's avatar
Jeremie Dimino committed
66
                if choice[0].lower != choice[0]:
67 68
                    answer = choice[0][0].lower()
                    break
Jeremie Dimino's avatar
Jeremie Dimino committed
69 70
            if answer == " ":
                cprint("Aucun choix par défaut!")
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
        else:
            answer = answer.lower()
            for choice in choices:
                if answer in choice[0].lower():
                    answer = choice[0][0].lower()
                    break
        if choices and answer == choice[0][0].lower():
            if len(choice) <= 2:
                return answer
            elif len(choice) == 3:
                return choice[2]
            elif type(choice[3]) == tuple:
                (message, choices) = choice[3]
            elif type(choice[3]) == str:
                print
                print choice[3]
            elif not choice[3]():
                return choice[2]
        if answer in ["h", "?"]:
            print
            cprint("Réponses possible:")
            for choice in choices:
                cprint("%s: %s" % (" ou ".join(list(choice[0])),
                                   ((len(choice) >= 2) and choice[1]) or "non documentée"))
            cprint("h ou ?: afficher cette aide")
            print
            cprint("<Espace>: accepter le choix par défault (celui qui est en majuscule)")
            print
        else:
            cprint("Choix invalide, essaies encore!")