sources-tree.js (4356B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ 4 5 import { createSelector } from "devtools/client/shared/vendor/reselect"; 6 7 /** 8 * Main selector to build the SourceTree, 9 * but this is also the source of data for the QuickOpen dialog. 10 * 11 * If no project directory root is set, this will return the thread items. 12 * Otherwise this will return the items where we set the directory root. 13 */ 14 export const getSourcesTreeSources = createSelector( 15 getProjectDirectoryRoot, 16 state => state.sourcesTree.threadItems, 17 (projectDirectoryRoot, threadItems) => { 18 // Only accept thread which have their thread attribute set. 19 // This may come late, if we receive ADD_SOURCES before INSERT_THREAD. 20 // Also filter out threads which have no sources, in case we had 21 // INSERT_THREAD with no ADD_SOURCES. 22 threadItems = threadItems.filter( 23 item => !!item.thread && !!item.children.length 24 ); 25 26 if (projectDirectoryRoot) { 27 const directory = getDirectoryForUniquePath( 28 projectDirectoryRoot, 29 threadItems 30 ); 31 if (directory) { 32 return directory.children; 33 } 34 return []; 35 } 36 37 return threadItems; 38 } 39 ); 40 41 // This is used by QuickOpen UI 42 /** 43 * Main selector for the QuickOpen dialog. 44 * 45 * The returns the list of all the reducer's source objects 46 * that are possibly displayed in the Source Tree. 47 * This doesn't return Source Tree Items, but the source objects. 48 */ 49 export const getDisplayedSourcesList = createSelector( 50 getSourcesTreeSources, 51 roots => { 52 const sources = []; 53 function walk(item) { 54 if (item.type == "source") { 55 sources.push(item.source); 56 } else { 57 for (const child of item.children) { 58 walk(child); 59 } 60 } 61 } 62 for (const root of roots) { 63 walk(root); 64 } 65 return sources; 66 } 67 ); 68 69 export function getExpandedState(state) { 70 return state.sourcesTree.expanded; 71 } 72 73 export function getFocusedSourceItem(state) { 74 return state.sourcesTree.focusedItem; 75 } 76 77 export function getProjectDirectoryRoot(state) { 78 return state.sourcesTree.projectDirectoryRoot; 79 } 80 81 export function getProjectDirectoryRootName(state) { 82 return state.sourcesTree.projectDirectoryRootName; 83 } 84 85 export function getProjectDirectoryRootFullName(state) { 86 return state.sourcesTree.projectDirectoryRootFullName; 87 } 88 89 export function getMainThreadProjectDirectoryRoots(state) { 90 return state.sourcesTree.mainThreadProjectDirectoryRoots; 91 } 92 93 /** 94 * Lookup for project root item, matching the given "unique path". 95 */ 96 function getDirectoryForUniquePath(projectRoot, threadItems) { 97 const sections = projectRoot.split("|"); 98 const thread = sections.shift(); 99 100 const threadItem = threadItems.find(item => item.uniquePath == thread); 101 if (!threadItem) { 102 dump( 103 `No thread item for: ${projectRoot} -- ${thread} -- ${Object.keys( 104 threadItems 105 )}\n` 106 ); 107 return null; 108 } 109 110 // If we selected a thread, the project root is for a Thread Item 111 // and it only contains `${thread}` 112 if (!sections.length) { 113 return threadItem; 114 } 115 116 const group = sections.shift(); 117 for (const child of threadItem.children) { 118 if (child.groupName != group) { 119 continue; 120 } 121 // In case we picked a group, return it... 122 // project root looked like this `${thread}|${group}` 123 if (!sections.length) { 124 return child; 125 } 126 // ..otherwise, we picked a directory, so look for it by traversing the tree 127 // project root looked like this `${thread}|${group}|${directoryPath}` 128 const path = sections.shift(); 129 return findPathInDirectory(child, path); 130 } 131 return null; 132 133 function findPathInDirectory(directory, path) { 134 for (const child of directory.children) { 135 if (child.type == "directory") { 136 // `path` should be the absolute path from the group/domain 137 if (child.path == path) { 138 return child; 139 } 140 // Ignore folders which doesn't match the beginning of the lookup path 141 if (!path.startsWith(child.path)) { 142 continue; 143 } 144 const match = findPathInDirectory(child, path); 145 if (match) { 146 return match; 147 } 148 } 149 } 150 return null; 151 } 152 }