@@ -34,6 +34,7 @@ import {
3434 getHiddenLocalTracks ,
3535 getInvertCallstack ,
3636 getHash ,
37+ getUrlState ,
3738} from 'firefox-profiler/selectors/url-state' ;
3839import {
3940 assertExhaustiveCheck ,
@@ -74,14 +75,17 @@ import type {
7475 TableViewOptions ,
7576 SelectionContext ,
7677 BottomBoxInfo ,
78+ IndexIntoFuncTable ,
7779} from 'firefox-profiler/types' ;
7880import {
7981 funcHasDirectRecursiveCall ,
8082 funcHasRecursiveCall ,
8183} from '../profile-logic/transforms' ;
8284import { changeStoredProfileNameInDb } from 'firefox-profiler/app-logic/uploaded-profiles-db' ;
85+ import { replaceHistoryWithUrlState } from 'firefox-profiler/app-logic/url-handling' ;
8386import type { TabSlug } from '../app-logic/tabs-handling' ;
8487import type { CallNodeInfo } from '../profile-logic/call-node-info' ;
88+ import type { SingleColumnSortState } from '../components/shared/TreeView' ;
8589import { intersectSets } from 'firefox-profiler/utils/set' ;
8690
8791/**
@@ -120,7 +124,7 @@ export function changeSelectedCallNode(
120124 const isInverted = getInvertCallstack ( getState ( ) ) ;
121125 dispatch ( {
122126 type : 'CHANGE_SELECTED_CALL_NODE' ,
123- isInverted,
127+ area : isInverted ? 'INVERTED_TREE' : 'NON_INVERTED_TREE' ,
124128 selectedCallNodePath,
125129 optionalExpandedToCallNodePath,
126130 threadsKey,
@@ -129,6 +133,62 @@ export function changeSelectedCallNode(
129133 } ;
130134}
131135
136+ export function changeLowerWingSelectedCallNode (
137+ threadsKey : ThreadsKey ,
138+ selectedCallNodePath : CallNodePath ,
139+ context : SelectionContext = { source : 'auto' }
140+ ) : Action {
141+ return {
142+ type : 'CHANGE_SELECTED_CALL_NODE' ,
143+ area : 'LOWER_WING' ,
144+ selectedCallNodePath,
145+ optionalExpandedToCallNodePath : [ ] ,
146+ threadsKey,
147+ context,
148+ } ;
149+ }
150+
151+ export function changeUpperWingSelectedCallNode (
152+ threadsKey : ThreadsKey ,
153+ selectedCallNodePath : CallNodePath ,
154+ context : SelectionContext = { source : 'auto' }
155+ ) : Action {
156+ return {
157+ type : 'CHANGE_SELECTED_CALL_NODE' ,
158+ area : 'UPPER_WING' ,
159+ selectedCallNodePath,
160+ optionalExpandedToCallNodePath : [ ] ,
161+ threadsKey,
162+ context,
163+ } ;
164+ }
165+
166+ /**
167+ * Select a function for a given thread in the function list.
168+ *
169+ * Replaces the current history entry rather than pushing a new one, so that
170+ * holding e.g. the down arrow key in the function list doesn't get rate-limited
171+ * by the browser and doesn't flood the back/forward history.
172+ */
173+ export function changeSelectedFunctionIndex (
174+ threadsKey : ThreadsKey ,
175+ selectedFunctionIndex : IndexIntoFuncTable | null ,
176+ context : SelectionContext = { source : 'auto' }
177+ ) : ThunkAction < void > {
178+ return ( dispatch , getState ) => {
179+ dispatch ( {
180+ type : 'CHANGE_SELECTED_FUNCTION' ,
181+ selectedFunctionIndex,
182+ threadsKey,
183+ context,
184+ } ) ;
185+ // Update window.history synchronously instead of waiting for the
186+ // UrlManager's componentDidUpdate, which is deferred by React's render
187+ // scheduling and would otherwise pushState a new entry.
188+ replaceHistoryWithUrlState ( getUrlState ( getState ( ) ) ) ;
189+ } ;
190+ }
191+
132192/**
133193 * This action is used when the user right clicks on a call node (in panels such
134194 * as the call tree, the flame chart, or the stack chart). It's especially used
@@ -137,10 +197,49 @@ export function changeSelectedCallNode(
137197export function changeRightClickedCallNode (
138198 threadsKey : ThreadsKey ,
139199 callNodePath : CallNodePath | null
200+ ) : ThunkAction < void > {
201+ return ( dispatch , getState ) => {
202+ const isInverted = getInvertCallstack ( getState ( ) ) ;
203+ dispatch ( {
204+ type : 'CHANGE_RIGHT_CLICKED_CALL_NODE' ,
205+ threadsKey,
206+ area : isInverted ? 'INVERTED_TREE' : 'NON_INVERTED_TREE' ,
207+ callNodePath,
208+ } ) ;
209+ } ;
210+ }
211+
212+ export function changeRightClickedFunctionIndex (
213+ threadsKey : ThreadsKey ,
214+ functionIndex : IndexIntoFuncTable | null
215+ ) : Action {
216+ return {
217+ type : 'CHANGE_RIGHT_CLICKED_FUNCTION' ,
218+ threadsKey,
219+ functionIndex,
220+ } ;
221+ }
222+
223+ export function changeLowerWingRightClickedCallNode (
224+ threadsKey : ThreadsKey ,
225+ callNodePath : CallNodePath | null
140226) : Action {
141227 return {
142228 type : 'CHANGE_RIGHT_CLICKED_CALL_NODE' ,
143229 threadsKey,
230+ area : 'LOWER_WING' ,
231+ callNodePath,
232+ } ;
233+ }
234+
235+ export function changeUpperWingRightClickedCallNode (
236+ threadsKey : ThreadsKey ,
237+ callNodePath : CallNodePath | null
238+ ) {
239+ return {
240+ type : 'CHANGE_RIGHT_CLICKED_CALL_NODE' ,
241+ threadsKey,
242+ area : 'UPPER_WING' ,
144243 callNodePath,
145244 } ;
146245}
@@ -207,6 +306,40 @@ export function selectSelfCallNode(
207306 } ;
208307}
209308
309+ /**
310+ * Like selectSelfCallNode, but selects the function of the self call node
311+ * instead. Used when the function list tab is active.
312+ */
313+ export function selectSelfFunction (
314+ threadsKey : ThreadsKey ,
315+ sampleIndex : IndexIntoSamplesTable | null
316+ ) : ThunkAction < void > {
317+ return ( dispatch , getState ) => {
318+ if ( sampleIndex === null || sampleIndex < 0 ) {
319+ dispatch ( changeSelectedFunctionIndex ( threadsKey , null ) ) ;
320+ return ;
321+ }
322+ const threadSelectors = getThreadSelectorsFromThreadsKey ( threadsKey ) ;
323+ const sampleCallNodes =
324+ threadSelectors . getSampleIndexToNonInvertedCallNodeIndexForFilteredThread (
325+ getState ( )
326+ ) ;
327+ if ( sampleIndex >= sampleCallNodes . length ) {
328+ dispatch ( changeSelectedFunctionIndex ( threadsKey , null ) ) ;
329+ return ;
330+ }
331+ const nonInvertedSelfCallNode = sampleCallNodes [ sampleIndex ] ;
332+ if ( nonInvertedSelfCallNode === null ) {
333+ dispatch ( changeSelectedFunctionIndex ( threadsKey , null ) ) ;
334+ return ;
335+ }
336+ const callNodeInfo = threadSelectors . getCallNodeInfo ( getState ( ) ) ;
337+ const funcIndex =
338+ callNodeInfo . getCallNodeTable ( ) . func [ nonInvertedSelfCallNode ] ;
339+ dispatch ( changeSelectedFunctionIndex ( threadsKey , funcIndex ) ) ;
340+ } ;
341+ }
342+
210343/**
211344 * This selects a set of thread from thread indexes.
212345 * Please use it in tests only.
@@ -1545,12 +1678,37 @@ export function changeExpandedCallNodes(
15451678 const isInverted = getInvertCallstack ( getState ( ) ) ;
15461679 dispatch ( {
15471680 type : 'CHANGE_EXPANDED_CALL_NODES' ,
1548- isInverted,
1681+ area : isInverted ? 'INVERTED_TREE' : 'NON_INVERTED_TREE' ,
15491682 threadsKey,
15501683 expandedCallNodePaths,
15511684 } ) ;
15521685 } ;
15531686}
1687+
1688+ export function changeLowerWingExpandedCallNodes (
1689+ threadsKey : ThreadsKey ,
1690+ expandedCallNodePaths : Array < CallNodePath >
1691+ ) : Action {
1692+ return {
1693+ type : 'CHANGE_EXPANDED_CALL_NODES' ,
1694+ area : 'LOWER_WING' ,
1695+ threadsKey,
1696+ expandedCallNodePaths,
1697+ } ;
1698+ }
1699+
1700+ export function changeUpperWingExpandedCallNodes (
1701+ threadsKey : ThreadsKey ,
1702+ expandedCallNodePaths : Array < CallNodePath >
1703+ ) : Action {
1704+ return {
1705+ type : 'CHANGE_EXPANDED_CALL_NODES' ,
1706+ area : 'UPPER_WING' ,
1707+ threadsKey,
1708+ expandedCallNodePaths,
1709+ } ;
1710+ }
1711+
15541712export function changeSelectedMarker (
15551713 threadsKey : ThreadsKey ,
15561714 selectedMarker : MarkerIndex | null ,
@@ -1615,6 +1773,31 @@ export function changeMarkersSearchString(searchString: string): Action {
16151773 } ;
16161774}
16171775
1776+ export function changeMarkerTableSort ( sort : SingleColumnSortState [ ] ) : Action {
1777+ return {
1778+ type : 'CHANGE_MARKER_TABLE_SORT' ,
1779+ sort,
1780+ } ;
1781+ }
1782+
1783+ export function changeFunctionListSort ( sort : SingleColumnSortState [ ] ) : Action {
1784+ return {
1785+ type : 'CHANGE_FUNCTION_LIST_SORT' ,
1786+ sort,
1787+ } ;
1788+ }
1789+
1790+ export function changeFunctionListSectionOpen (
1791+ section : 'descendants' | 'ancestors' | 'self' ,
1792+ isOpen : boolean
1793+ ) : Action {
1794+ return {
1795+ type : 'CHANGE_FUNCTION_LIST_SECTION_OPEN' ,
1796+ section,
1797+ isOpen,
1798+ } ;
1799+ }
1800+
16181801export function changeNetworkSearchString ( searchString : string ) : Action {
16191802 return {
16201803 type : 'CHANGE_NETWORK_SEARCH_STRING' ,
@@ -2015,6 +2198,7 @@ export function toggleBottomBoxFullscreen(): ThunkAction<void> {
20152198export function handleCallNodeTransformShortcut (
20162199 event : React . KeyboardEvent < HTMLElement > ,
20172200 threadsKey : ThreadsKey ,
2201+ callNodeInfo : CallNodeInfo ,
20182202 callNodeIndex : IndexIntoCallNodeTable
20192203) : ThunkAction < void > {
20202204 return ( dispatch , getState ) => {
@@ -2023,7 +2207,6 @@ export function handleCallNodeTransformShortcut(
20232207 }
20242208 const threadSelectors = getThreadSelectorsFromThreadsKey ( threadsKey ) ;
20252209 const unfilteredThread = threadSelectors . getThread ( getState ( ) ) ;
2026- const callNodeInfo = threadSelectors . getCallNodeInfo ( getState ( ) ) ;
20272210 const implementation = getImplementationFilter ( getState ( ) ) ;
20282211 const inverted = getInvertCallstack ( getState ( ) ) ;
20292212 const callNodePath = callNodeInfo . getCallNodePathFromIndex ( callNodeIndex ) ;
@@ -2133,3 +2316,100 @@ export function handleCallNodeTransformShortcut(
21332316 }
21342317 } ;
21352318}
2319+
2320+ export function handleFunctionTransformShortcut (
2321+ event : React . KeyboardEvent < HTMLElement > ,
2322+ threadsKey : ThreadsKey ,
2323+ funcIndex : IndexIntoFuncTable
2324+ ) : ThunkAction < void > {
2325+ return ( dispatch , getState ) => {
2326+ if ( event . metaKey || event . ctrlKey || event . altKey ) {
2327+ return ;
2328+ }
2329+ const threadSelectors = getThreadSelectorsFromThreadsKey ( threadsKey ) ;
2330+ const callNodeInfo = threadSelectors . getCallNodeInfo ( getState ( ) ) ;
2331+ const implementation = getImplementationFilter ( getState ( ) ) ;
2332+ const callNodeTable = callNodeInfo . getCallNodeTable ( ) ;
2333+ const unfilteredThread = threadSelectors . getThread ( getState ( ) ) ;
2334+
2335+ switch ( event . key ) {
2336+ case 'f' :
2337+ dispatch (
2338+ addTransformToStack ( threadsKey , {
2339+ type : 'focus-function' ,
2340+ funcIndex,
2341+ } )
2342+ ) ;
2343+ break ;
2344+ case 'S' :
2345+ dispatch (
2346+ addTransformToStack ( threadsKey , {
2347+ type : 'focus-self' ,
2348+ funcIndex,
2349+ implementation,
2350+ } )
2351+ ) ;
2352+ break ;
2353+ case 'm' :
2354+ dispatch (
2355+ addTransformToStack ( threadsKey , {
2356+ type : 'merge-function' ,
2357+ funcIndex,
2358+ } )
2359+ ) ;
2360+ break ;
2361+ case 'd' :
2362+ dispatch (
2363+ addTransformToStack ( threadsKey , {
2364+ type : 'drop-function' ,
2365+ funcIndex,
2366+ } )
2367+ ) ;
2368+ break ;
2369+ case 'C' : {
2370+ const resourceIndex = unfilteredThread . funcTable . resource [ funcIndex ] ;
2371+ dispatch (
2372+ addCollapseResourceTransformToStack (
2373+ threadsKey ,
2374+ resourceIndex ,
2375+ implementation
2376+ )
2377+ ) ;
2378+ break ;
2379+ }
2380+ case 'r' : {
2381+ if ( funcHasRecursiveCall ( callNodeTable , funcIndex ) ) {
2382+ dispatch (
2383+ addTransformToStack ( threadsKey , {
2384+ type : 'collapse-recursion' ,
2385+ funcIndex,
2386+ } )
2387+ ) ;
2388+ }
2389+ break ;
2390+ }
2391+ case 'R' : {
2392+ if ( funcHasDirectRecursiveCall ( callNodeTable , funcIndex ) ) {
2393+ dispatch (
2394+ addTransformToStack ( threadsKey , {
2395+ type : 'collapse-direct-recursion' ,
2396+ funcIndex,
2397+ implementation,
2398+ } )
2399+ ) ;
2400+ }
2401+ break ;
2402+ }
2403+ case 'c' :
2404+ dispatch (
2405+ addTransformToStack ( threadsKey , {
2406+ type : 'collapse-function-subtree' ,
2407+ funcIndex,
2408+ } )
2409+ ) ;
2410+ break ;
2411+ default :
2412+ // This did not match a function transform.
2413+ }
2414+ } ;
2415+ }
0 commit comments