content: #!/usr/bin/python
  
  # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
  #
  # This source code is licensed under the MIT license found in the
  # LICENSE file in the root directory of this source tree.
  
  import os
  import re
  
  import fbchisellldbbase as fb
  import fbchisellldbobjcruntimehelpers as objc
  import fbchisellldbviewcontrollerhelpers as vcHelpers
  import lldb
  
  
  def lldbcommands():
      return [FBFindViewControllerCommand(), FBFindViewCommand(), FBTapLoggerCommand()]
  
  
  class FBFindViewControllerCommand(fb.FBCommand):
      def name(self):
          return "fvc"
  
      def description(self):
          return "Find the view controllers whose class names match classNameRegex and puts the address of first on the clipboard."
  
      def options(self):
          return [
              fb.FBCommandArgument(
                  short="-n",
                  long="--name",
                  arg="classNameRegex",
                  type="string",
                  help="The view-controller-class regex to search the view controller hierarchy for.",
              ),
              fb.FBCommandArgument(
                  short="-v",
                  long="--view",
                  arg="view",
                  type="UIView",
                  help="This function will print the View Controller that owns this view.",
              ),
          ]
  
      def run(self, arguments, options):
          if options.classNameRegex and options.view:
              print("Do not set both the --name and --view flags")
          elif options.view:
              self.findOwningViewController(options.view)
          else:
              output = vcHelpers.viewControllerRecursiveDescription(
                  "(id)[[[UIApplication sharedApplication] keyWindow] rootViewController]"
              )
              searchString = (
                  options.classNameRegex if options.classNameRegex else arguments[0]
              )
              printMatchesInViewOutputStringAndCopyFirstToClipboard(searchString, output)
  
      def findOwningViewController(self, object):
          while object:
              if self.isViewController(object):
                  description = fb.evaluateExpressionValue(object).GetObjectDescription()
                  print("Found the owning view controller.\n{}".format(description))
                  cmd = 'echo {} | tr -d "\n" | pbcopy'.format(object)
                  os.system(cmd)
                  return
              else:
                  object = self.nextResponder(object)
          print("Could not find an owning view controller")
  
      @staticmethod
      def isViewController(object):
          command = "[(id){} isKindOfClass:[UIViewController class]]".format(object)
          isVC = fb.evaluateBooleanExpression(command)
          return isVC
  
      @staticmethod
      def nextResponder(object):
          command = "[((id){}) nextResponder]".format(object)
          nextResponder = fb.evaluateObjectExpression(command)
          try:
              if int(nextResponder, 0):
                  return nextResponder
              else:
                  return None
          except Exception:
              return None
  
  
  class FBFindViewCommand(fb.FBCommand):
      def name(self):
          return "fv"
  
      def description(self):
          return "Find the views whose class names match classNameRegex and puts the address of first on the clipboard."
  
      def args(self):
          return [
              fb.FBCommandArgument(
                  arg="classNameRegex",
                  type="string",
                  help="The view-class regex to search the view hierarchy for.",
              )
          ]
  
      def run(self, arguments, options):
          output = fb.evaluateExpressionValue(
              "(id)[[[UIApplication sharedApplication] keyWindow] recursiveDescription]"
          ).GetObjectDescription()
          printMatchesInViewOutputStringAndCopyFirstToClipboard(arguments[0], output)
  
  
  def printMatchesInViewOutputStringAndCopyFirstToClipboard(needle, haystack):
      first = None
      for match in re.finditer(
          ".*<.*(" + needle + ")\\S*: (0x[0-9a-fA-F]*);.*", haystack, re.IGNORECASE
      ):
          view = match.groups()[-1]
          className = fb.evaluateExpressionValue(
              "(id)[(" + view + ") class]"
          ).GetObjectDescription()
          print("{} {}".format(view, className))
          if first is None:
              first = view
              cmd = 'echo %s | tr -d "\n" | pbcopy' % view
              os.system(cmd)
  
  
  class FBTapLoggerCommand(fb.FBCommand):
      def name(self):
          return "taplog"
  
      def description(self):
          return "Log tapped view to the console."
  
      def run(self, arguments, options):
          parameterExpr = objc.functionPreambleExpressionForObjectParameterAtIndex(0)
          breakpoint = lldb.debugger.GetSelectedTarget().BreakpointCreateByName(
              "-[UIApplication sendEvent:]"
          )
          breakpoint.SetCondition(
              "(int)["
              + parameterExpr
              + " type] == 0 && (int)[[["
              + parameterExpr
              + " allTouches] anyObject] phase] == 0"
          )
          breakpoint.SetOneShot(True)
  
          callback_name = taplog_callback.__qualname__
          # Import the callback so LLDB can see it
          lldb.debugger.HandleCommand(
              "script from %s import %s" % (__name__, callback_name)
          )
          breakpoint.SetScriptCallbackFunction(callback_name)
  
          lldb.debugger.SetAsync(True)
          lldb.debugger.HandleCommand("continue")
  
  
  def taplog_callback(frame, bp_loc, internal_dict):
      parameterExpr = objc.functionPreambleExpressionForObjectParameterAtIndex(0)
      print(
          "Gesture Recognizers:\n{}".format(
              fb.describeObject(
                  "[[[%s allTouches] anyObject] gestureRecognizers]" % (parameterExpr)
              )
          )
      )
      print(
          "View:\n{}".format(
              fb.describeObject("[[[%s allTouches] anyObject] view]" % (parameterExpr))
          )
      )
      # We don't want to proceed event (click on button for example), so we just skip it
      lldb.debugger.HandleCommand("thread return")
  