code: def ask_choice(
      *prompt: Token, choices: List[Any], func_desc: Optional[FuncDesc] = None
  ) -> Any:
      
      if func_desc is None:
          func_desc = lambda x: str(x)
      tokens = get_ask_tokens(prompt)
      info(*tokens)
      choices.sort(key=func_desc)
      for i, choice in enumerate(choices, start=1):
          choice_desc = func_desc(choice)
          info("  ", blue, "%i" % i, reset, choice_desc)
      keep_asking = True
      res = None
      while keep_asking:
          answer = read_input()
          if not answer:
              return None
          try:
              index = int(answer)
          except ValueError:
              info("Please enter a valid number")
              continue
          if index not in range(1, len(choices) + 1):
              info(str(index), "is out of range")
              continue
          res = choices[index - 1]
          keep_asking = False
  
      return res
docs: Ask the user to choose from a list of choices.
  
      :return: the selected choice
  
      ``func_desc`` will be called on every list item for displaying
      and sorting the list. If not given, will default to
      the identity function.
  
      Will loop until:
          * the user enters a valid index
          * or leaves the prompt empty
  
      In the last case, None will be returned