commands/FBFlickerCommands.py (128 lines of code) (raw):

#!/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 sys import fbchisellldbbase as fb import fbchisellldbobjcruntimehelpers as runtimeHelpers import fbchisellldbviewhelpers as viewHelpers import lldb def lldbcommands(): return [FBFlickerViewCommand(), FBViewSearchCommand()] class FBFlickerViewCommand(fb.FBCommand): def name(self): return "flicker" def description(self): return "Quickly show and hide a view to quickly help visualize where it is." def args(self): return [ fb.FBCommandArgument( arg="viewOrLayer", type="UIView/NSView*", help="The view to flicker." ) ] def run(self, arguments, options): object = fb.evaluateObjectExpression(arguments[0]) isHidden = fb.evaluateBooleanExpression("[" + object + " isHidden]") shouldHide = not isHidden for _ in range(0, 2): viewHelpers.setViewHidden(object, shouldHide) viewHelpers.setViewHidden(object, isHidden) class FBViewSearchCommand(fb.FBCommand): def name(self): return "vs" def description(self): return "Interactively search for a view by walking the hierarchy." def args(self): return [ fb.FBCommandArgument(arg="view", type="UIView*", help="The view to border.") ] def run(self, arguments, options): print( "\nUse the following and (q) to quit.\n(w) move to superview\n(s) move to first subview\n(a) move to previous sibling\n(d) move to next sibling\n(p) print the hierarchy\n" ) object = fb.evaluateInputExpression(arguments[0]) walker = FlickerWalker(object) walker.run() class FlickerWalker: def __init__(self, startView): self.setCurrentView(startView) def run(self): self.keepRunning = True initialAsync = lldb.debugger.GetAsync() # Needed so XCode doesn't hang if tap on Continue while lldb # is waiting for user input in 'vs' mode lldb.debugger.SetAsync(True) while self.keepRunning: charRead = sys.stdin.readline().rstrip("\n") self.inputCallback(charRead) else: lldb.debugger.SetAsync(initialAsync) def inputCallback(self, input): oldView = self.currentView if input == "q": cmd = 'echo %s | tr -d "\n" | pbcopy' % oldView os.system(cmd) print( "\nI hope " + oldView + " was what you were looking for. I put it on your clipboard." ) viewHelpers.unmaskView(oldView) self.keepRunning = False elif input == "w": v = superviewOfView(self.currentView) if not v: print("There is no superview. Where are you trying to go?!") self.setCurrentView(v, oldView) elif input == "s": v = firstSubviewOfView(self.currentView) if not v: print("\nThe view has no subviews.\n") self.setCurrentView(v, oldView) elif input == "d": v = nthSiblingOfView(self.currentView, -1) if v == oldView: print("\nThere are no sibling views to this view.\n") self.setCurrentView(v, oldView) elif input == "a": v = nthSiblingOfView(self.currentView, 1) if v == oldView: print("\nThere are no sibling views to this view.\n") self.setCurrentView(v, oldView) elif input == "p": recursionName = "recursiveDescription" isMac = runtimeHelpers.isMacintoshArch() if isMac: recursionName = "_subtreeDescription" print(fb.describeObject("[(id){} {}]".format(oldView, recursionName))) else: print("\nI really have no idea what you meant by '" + input + "'... =\\\n") def setCurrentView(self, view, oldView=None): if view: self.currentView = view if oldView: viewHelpers.unmaskView(oldView) viewHelpers.maskView(self.currentView, "red", "0.4") print(fb.describeObject(view)) def superviewOfView(view): superview = fb.evaluateObjectExpression("[" + view + " superview]") if int(superview, 16) == 0: return None return superview def subviewsOfView(view): return fb.evaluateObjectExpression("[" + view + " subviews]") def firstSubviewOfView(view): subviews = subviewsOfView(view) numViews = fb.evaluateIntegerExpression("[(id)" + subviews + " count]") if numViews == 0: return None else: return fb.evaluateObjectExpression("[" + subviews + " objectAtIndex:0]") def nthSiblingOfView(view, n): subviews = subviewsOfView(superviewOfView(view)) numViews = fb.evaluateIntegerExpression("[(id)" + subviews + " count]") idx = fb.evaluateIntegerExpression( "[(id)" + subviews + " indexOfObject:" + view + "]" ) newIdx = idx + n while newIdx < 0: newIdx += numViews newIdx = newIdx % numViews return fb.evaluateObjectExpression( "[(id)" + subviews + " objectAtIndex:" + str(newIdx) + "]" )