text: #!/usr/bin/env python
  """Main Terminal Module"""
  __docformat__ = "numpy"
  
  import os
  import argparse
  import difflib
  import logging
  import sys
  from typing import List, Union
  
  from prompt_toolkit.completion import NestedCompleter
  
  from gamestonk_terminal import feature_flags as gtff
  from gamestonk_terminal.helper_funcs import (
      get_flair,
      system_clear,
  )
  from gamestonk_terminal.loggers import setup_logging
  from gamestonk_terminal.menu import session
  from gamestonk_terminal.terminal_helper import (
      about_us,
      bootup,
      check_api_keys,
      print_goodbye,
      reset,
      update_terminal,
  )
  
  # pylint: disable=too-many-public-methods,import-outside-toplevel
  
  logger = logging.getLogger(__name__)
  
  
  class TerminalController:
      """Terminal Controller class"""
  
      CHOICES = [
          "cls",
          "h",
          "?",
          "help",
          "q",
          "quit",
          "..",
          "exit",
          "r",
          "reset",
      ]
      CHOICES_COMMANDS = [
          "update",
          "about",
          "keys",
      ]
      CHOICES_MENUS = [
          "stocks",
          "economy",
          "crypto",
          "portfolio",
          "forex",
          "etf",
          "reports",
          "resources",
          "funds",
      ]
      CHOICES += CHOICES_COMMANDS
      CHOICES += CHOICES_MENUS
  
      def __init__(self, jobs_cmds: List[str] = None):
          """Constructor"""
          self.t_parser = argparse.ArgumentParser(add_help=False, prog="terminal")
          self.t_parser.add_argument(
              "cmd",
              choices=self.CHOICES,
          )
  
          self.completer: Union[None, NestedCompleter] = None
  
          if session and gtff.USE_PROMPT_TOOLKIT:
              choices: dict = {c: None for c in self.CHOICES}
  
              self.completer = NestedCompleter.from_nested_dict(choices)
  
          self.queue: List[str] = list()
  
          if jobs_cmds:
              # close the eyes if the user forgets the initial `/`
              if len(jobs_cmds) > 0:
                  if jobs_cmds[0][0] != "/":
                      jobs_cmds[0] = f"/{jobs_cmds[0]}"
  
              self.queue = " ".join(jobs_cmds).split("/")
  
          self.update_succcess = False
  
      def print_help(self):
          """Print help"""
          help_text = """
  Multiple jobs queue (where each '/' denotes a new command). E.g.
      /stocks $ disc/ugs -n 3/../load tsla/candle
  
  If you want to jump from crypto/ta to stocks you can use an absolute path that starts with a slash (/). E.g.
      /crypto/ta $ /stocks
  
  The previous logic also holds for when launching the terminal. E.g.
      $ python terminal.py /stocks/disc/ugs -n 3/../load tsla/candle
  
  The main commands you should be aware when navigating through the terminal are:
      cls             clear the screen
      help / h / ?    help menu
      quit / q / ..   quit this menu and go one menu above
      exit            exit the terminal
      reset / r       reset the terminal and reload configs from the current location
  
      about           about us
      update          update terminal automatically
      keys            check for status of API keys
  
  >   stocks
  >   crypto
  >   etf
  >   economy
  >   forex
  >   funds
  >   portfolio
  >   reports
  >   resources
      """
          print(help_text)
  
      def switch(self, an_input: str):
          """Process and dispatch input
  
          Returns
          -------
          List[str]
              List of commands in the queue to execute
          """
          # Empty command
          if not an_input:
              print("")
              return self.queue
  
          # Navigation slash is being used
          if "/" in an_input:
              actions = an_input.split("/")
              # Absolute path is specified.
              if not actions[0]:
                  # Since we are already in home we can pick up the first instruction
                  an_input = actions[1]
                  idx_to_start = 2
              # Relative path so execute first instruction
              else:
                  an_input = actions[0]
                  idx_to_start = 1
  
              # Add all instructions to the queue
              for cmd in actions[idx_to_start:][::-1]:
                  if cmd:
                      self.queue.insert(0, cmd)
  
          (known_args, other_args) = self.t_parser.parse_known_args(an_input.split())
  
          if known_args.cmd:
              if known_args.cmd in ("..", "q"):
                  known_args.cmd = "quit"
              elif known_args.cmd in ("?", "h"):
                  known_args.cmd = "help"
              elif known_args.cmd == "r":
                  known_args.cmd = "reset"
  
          getattr(
              self,
              "call_" + known_args.cmd,
              lambda _: "Command not recognized!",
          )(other_args)
  
          return self.queue
  
      def call_cls(self, _):
          """Process cls command"""
          system_clear()
  
      def call_help(self, _):
          """Process help command"""
          self.print_help()
  
      def call_quit(self, _):
          """Process quit menu command"""
          print("")
          self.queue.insert(0, "quit")
  
      def call_exit(self, _):
          """Process exit terminal command"""
          self.queue.insert(0, "quit")
  
      def call_reset(self, _):
          """Process reset command"""
          # has been dealt with before
  
      def call_update(self, _):
          """Process update command"""
          self.update_succcess = not update_terminal()
  
      def call_keys(self, _):
          """Process keys command"""
          check_api_keys()
  
      def call_about(self, _):
          """Process about command"""
          about_us()
  
      def call_stocks(self, _):
          """Process stocks command"""
          from gamestonk_terminal.stocks import stocks_controller
  
          self.queue = stocks_controller.menu("", self.queue)
  
      def call_crypto(self, _):
          """Process crypto command"""
          from gamestonk_terminal.cryptocurrency import crypto_controller
  
          self.queue = crypto_controller.menu(queue=self.queue)
  
      def call_economy(self, _):
          """Process economy command"""
          from gamestonk_terminal.economy import economy_controller
  
          self.queue = economy_controller.menu(self.queue)
  
      def call_etf(self, _):
          """Process etf command"""
          from gamestonk_terminal.etf import etf_controller
  
          self.queue = etf_controller.menu(self.queue)
  
      def call_funds(self, _):
          """Process etf command"""
          from gamestonk_terminal.mutual_funds import mutual_fund_controller
  
          self.queue = mutual_fund_controller.menu(self.queue)
  
      def call_forex(self, _):
          """Process forex command"""
          from gamestonk_terminal.forex import forex_controller
  
          self.queue = forex_controller.menu(self.queue)
  
      def call_reports(self, _):
          """Process reports command"""
          from gamestonk_terminal.reports import reports_controller
  
          self.queue = reports_controller.menu(self.queue)
  
      def call_resources(self, _):
          """Process resources command"""
          from gamestonk_terminal.resources import resources_controller
  
          self.queue = resources_controller.menu(self.queue)
  
      def call_portfolio(self, _):
          """Process portfolio command"""
          from gamestonk_terminal.portfolio import portfolio_controller
  
          self.queue = portfolio_controller.menu(self.queue)
  
  
  def terminal(jobs_cmds: List[str] = None):
      """Terminal Menu"""
      setup_logging()
  
      logger.info("Terminal started")
  
      ret_code = 1
      t_controller = TerminalController(jobs_cmds)
      an_input = ""
  
      if not jobs_cmds:
          bootup()
  
      while ret_code:
          if gtff.ENABLE_QUICK_EXIT:
              print("Quick exit enabled")
              break
  
          # There is a command in the queue
          if t_controller.queue and len(t_controller.queue) > 0:
              # If the command is quitting the menu we want to return in here
              if t_controller.queue[0] in ("q", "..", "quit"):
                  print("")
                  if len(t_controller.queue) > 1:
                      return t_controller.queue[1:]
                  return []
  
              # Consume 1 element from the queue
              an_input = t_controller.queue[0]
              t_controller.queue = t_controller.queue[1:]
  
              # Print the current location because this was an instruction and we want user to know what was the action
              if an_input and an_input.split(" ")[0] in t_controller.CHOICES_COMMANDS:
                  print(f"{get_flair()} / $ {an_input}")
  
          # Get input command from user
          else:
              # Display help menu when entering on this menu from a level above
              if not an_input:
                  t_controller.print_help()
  
              # Get input from user using auto-completion
              if session and gtff.USE_PROMPT_TOOLKIT:
                  an_input = session.prompt(
                      f"{get_flair()} / $ ",
                      completer=t_controller.completer,
                      search_ignore_case=True,
                  )
              # Get input from user without auto-completion
              else:
                  an_input = input(f"{get_flair()} / $ ")
  
          try:
              # Process the input command
              t_controller.queue = t_controller.switch(an_input)
  
              if an_input in ("q", "quit", "..", "exit"):
                  print_goodbye()
                  break
  
              # Check if the user wants to reset application
              if an_input in ("r", "reset") or t_controller.update_succcess:
                  ret_code = reset(
                      t_controller.queue if len(t_controller.queue) > 0 else []
                  )
                  if ret_code != 0:
                      print_goodbye()
                      break
  
          except SystemExit:
              print(f"\nThe command '{an_input}' doesn't exist on the / menu", end="")
              similar_cmd = difflib.get_close_matches(
                  an_input.split(" ")[0] if " " in an_input else an_input,
                  t_controller.CHOICES,
                  n=1,
                  cutoff=0.7,
              )
              if similar_cmd:
                  if " " in an_input:
                      candidate_input = (
                          f"{similar_cmd[0]} {' '.join(an_input.split(' ')[1:])}"
                      )
                      if candidate_input == an_input:
                          an_input = ""
                          t_controller.queue = []
                          print("\n")
                          continue
                      an_input = candidate_input
                  else:
                      an_input = similar_cmd[0]
  
                  print(f" Replacing by '{an_input}'.")
                  t_controller.queue.insert(0, an_input)
              else:
                  print("\n")
  
  
  if __name__ == "__main__":
      if len(sys.argv) > 1:
          if ".gst" in sys.argv[1]:
              if os.path.isfile(sys.argv[1]):
                  with open(sys.argv[1]) as fp:
                      simulate_argv = f"/{'/'.join([line.rstrip() for line in fp])}"
                      terminal(simulate_argv.replace("//", "/home/").split())
              else:
                  print(
                      f"The file '{sys.argv[1]}' doesn't exist. Launching terminal without any configuration.\n"
                  )
                  terminal()
          else:
              terminal(sys.argv[1:])
      else:
          terminal()
  