diff --git a/devtools/client/debugger/src/actions/sources/select.js b/devtools/client/debugger/src/actions/sources/select.js index 8e4fd3339b85..8b8ad209610a 100644 --- a/devtools/client/debugger/src/actions/sources/select.js +++ b/devtools/client/debugger/src/actions/sources/select.js @@ -16,13 +16,12 @@ import { getSourcesForTabs } from "../../reducers/tabs"; import { setSymbols } from "./symbols"; import { setInScopeLines } from "../ast"; import { closeActiveSearch, updateActiveFileSearch } from "../ui"; -import { isFulfilled } from "../../utils/async-value"; import { togglePrettyPrint } from "./prettyPrint"; import { addTab, closeTab } from "../tabs"; import { loadSourceText } from "./loadSourceText"; import { prefs } from "../../utils/prefs"; -import { shouldPrettyPrint, isMinified } from "../../utils/source"; +import { isMinified } from "../../utils/source"; import { createLocation } from "../../utils/location"; import { mapLocation } from "../../utils/source-maps"; @@ -33,6 +32,7 @@ import { getActiveSearch, getSelectedLocation, getSelectedSource, + canPrettyPrintSource, } from "../../selectors"; import type { @@ -169,19 +169,12 @@ export function selectLocation( return; } const sourceWithContent = getSourceWithContent(getState(), source.id); - const sourceContent = - sourceWithContent.content && isFulfilled(sourceWithContent.content) - ? sourceWithContent.content.value - : null; if ( keepContext && prefs.autoPrettyPrint && !getPrettySource(getState(), loadedSource.id) && - shouldPrettyPrint( - loadedSource, - sourceContent || { type: "text", value: "", contentType: undefined } - ) && + canPrettyPrintSource(getState(), loadedSource.id) && isMinified(sourceWithContent) ) { await dispatch(togglePrettyPrint(cx, loadedSource.id)); diff --git a/devtools/client/debugger/src/components/Editor/EditorMenu.js b/devtools/client/debugger/src/components/Editor/EditorMenu.js index 48c1a4335bde..1a87d4ab1cab 100644 --- a/devtools/client/debugger/src/components/Editor/EditorMenu.js +++ b/devtools/client/debugger/src/components/Editor/EditorMenu.js @@ -7,13 +7,16 @@ import { Component } from "react"; import { connect } from "../../utils/connect"; import { showMenu } from "devtools-contextmenu"; +import { isOriginalId } from "devtools-source-map"; import { getSourceLocationFromMouseEvent } from "../../utils/editor"; +import { isPretty } from "../../utils/source"; import { getPrettySource, getIsPaused, getCurrentThread, getThreadContext, + isSourceWithMap, } from "../../selectors"; import { editorMenuItems, editorItemActions } from "./menus/editor"; @@ -28,7 +31,7 @@ type Props = { editorActions: EditorItemActions, clearContextMenu: () => void, editor: SourceEditor, - hasPrettySource: boolean, + hasMappedLocation: boolean, isPaused: boolean, selectedSource: SourceWithContent, }; @@ -49,7 +52,7 @@ class EditorMenu extends Component { editor, selectedSource, editorActions, - hasPrettySource, + hasMappedLocation, isPaused, contextMenu: event, } = props; @@ -67,7 +70,7 @@ class EditorMenu extends Component { cx, editorActions, selectedSource, - hasPrettySource, + hasMappedLocation, location, isPaused, selectionText: editor.codeMirror.getSelection().trim(), @@ -84,7 +87,11 @@ class EditorMenu extends Component { const mapStateToProps = (state, props) => ({ cx: getThreadContext(state), isPaused: getIsPaused(state, getCurrentThread(state)), - hasPrettySource: !!getPrettySource(state, props.selectedSource.id), + hasMappedLocation: + (isOriginalId(props.selectedSource.id) || + isSourceWithMap(state, props.selectedSource.id) || + isPretty(props.selectedSource)) && + !getPrettySource(state, props.selectedSource.id), }); const mapDispatchToProps = dispatch => ({ diff --git a/devtools/client/debugger/src/components/Editor/Footer.js b/devtools/client/debugger/src/components/Editor/Footer.js index c7663e941903..7f1f9d4ea5bd 100644 --- a/devtools/client/debugger/src/components/Editor/Footer.js +++ b/devtools/client/debugger/src/components/Editor/Footer.js @@ -14,15 +14,16 @@ import { getContext, } from "../../selectors"; -import { isFulfilled } from "../../utils/async-value"; import { isPretty, getFilename, isOriginal, shouldBlackbox, } from "../../utils/source"; -import { getGeneratedSource } from "../../reducers/sources"; -import { shouldShowPrettyPrint } from "../../utils/editor"; +import { + getGeneratedSource, + canPrettyPrintSource, +} from "../../reducers/sources"; import { PaneToggleButton } from "../shared/Button"; import AccessibleImage from "../shared/AccessibleImage"; @@ -42,6 +43,7 @@ type Props = { mappedSource: Source, endPanelCollapsed: boolean, horizontal: boolean, + canPrettyPrint: boolean, togglePrettyPrint: typeof actions.togglePrettyPrint, toggleBlackBox: typeof actions.toggleBlackBox, jumpToMappedLocation: typeof actions.jumpToMappedLocation, @@ -84,7 +86,12 @@ class SourceFooter extends PureComponent { } prettyPrintButton() { - const { cx, selectedSource, togglePrettyPrint } = this.props; + const { + cx, + selectedSource, + canPrettyPrint, + togglePrettyPrint, + } = this.props; if (!selectedSource) { return; @@ -98,16 +105,7 @@ class SourceFooter extends PureComponent { ); } - const sourceContent = - selectedSource.content && isFulfilled(selectedSource.content) - ? selectedSource.content.value - : null; - if ( - !shouldShowPrettyPrint( - selectedSource, - sourceContent || { type: "text", value: "", contentType: undefined } - ) - ) { + if (!canPrettyPrint) { return; } @@ -280,6 +278,9 @@ const mapStateToProps = state => { selectedSource ? selectedSource.id : null ), endPanelCollapsed: getPaneCollapse(state, "end"), + canPrettyPrint: selectedSource + ? canPrettyPrintSource(state, selectedSource.id) + : false, }; }; diff --git a/devtools/client/debugger/src/components/Editor/menus/editor.js b/devtools/client/debugger/src/components/Editor/menus/editor.js index 9157ce0f6f7f..ae7034eda58e 100644 --- a/devtools/client/debugger/src/components/Editor/menus/editor.js +++ b/devtools/client/debugger/src/components/Editor/menus/editor.js @@ -9,7 +9,6 @@ import { isOriginalId } from "devtools-source-map"; import { copyToTheClipboard } from "../../../utils/clipboard"; import { - isPretty, getRawSourceURL, getFilename, shouldBlackbox, @@ -29,10 +28,6 @@ import type { ThreadContext, } from "../../../types"; -function isMapped(selectedSource) { - return isOriginalId(selectedSource.id) || !!selectedSource.sourceMapURL; -} - export const continueToHereItem = ( cx: ThreadContext, location: SourceLocation, @@ -88,7 +83,7 @@ const jumpToMappedLocationItem = ( cx: Context, selectedSource: Source, location: SourceLocation, - hasPrettySource: boolean, + hasMappedLocation: boolean, editorActions: EditorItemActions ) => ({ id: "node-menu-jump", @@ -99,8 +94,7 @@ const jumpToMappedLocationItem = ( : L10N.getStr("original") ), accesskey: L10N.getStr("editor.jumpToMappedLocation1.accesskey"), - disabled: - (!isMapped(selectedSource) && !isPretty(selectedSource)) || hasPrettySource, + disabled: !hasMappedLocation, click: () => editorActions.jumpToMappedLocation(cx, location), }); @@ -171,7 +165,7 @@ export function editorMenuItems({ selectedSource, location, selectionText, - hasPrettySource, + hasMappedLocation, isTextSelected, isPaused, }: { @@ -180,7 +174,7 @@ export function editorMenuItems({ selectedSource: SourceWithContent, location: SourceLocation, selectionText: string, - hasPrettySource: boolean, + hasMappedLocation: boolean, isTextSelected: boolean, isPaused: boolean, }) { @@ -196,7 +190,7 @@ export function editorMenuItems({ cx, selectedSource, location, - hasPrettySource, + hasMappedLocation, editorActions ), continueToHereItem(cx, location, isPaused, editorActions), diff --git a/devtools/client/debugger/src/reducers/sources.js b/devtools/client/debugger/src/reducers/sources.js index 93abfaf47966..f7d28b2c3efd 100644 --- a/devtools/client/debugger/src/reducers/sources.js +++ b/devtools/client/debugger/src/reducers/sources.js @@ -17,6 +17,8 @@ import { isGenerated, isOriginal as isOriginalSource, getPlainUrl, + isPretty, + isJavaScript, } from "../utils/source"; import { createInitial, @@ -37,7 +39,14 @@ import { } from "../utils/resource"; import { findPosition } from "../utils/breakpoint/breakpointPositions"; -import * as asyncValue from "../utils/async-value"; +import { + pending, + fulfilled, + rejected, + asSettled, + isFulfilled, +} from "../utils/async-value"; + import type { AsyncValue, SettledValue } from "../utils/async-value"; import { originalToGeneratedId } from "devtools-source-map"; import { prefs } from "../utils/prefs"; @@ -260,7 +269,7 @@ const resourceAsSourceBase = memoizeResourceShallow( const resourceAsSourceWithContent = memoizeResourceShallow( ({ content, ...source }: SourceResource): SourceWithContent => ({ ...source, - content: asyncValue.asSettled(content), + content: asSettled(content), }) ); @@ -417,17 +426,17 @@ function updateLoadedState( let content; if (action.status === "start") { - content = asyncValue.pending(); + content = pending(); } else if (action.status === "error") { - content = asyncValue.rejected(action.error); + content = rejected(action.error); } else if (typeof action.value.text === "string") { - content = asyncValue.fulfilled({ + content = fulfilled({ type: "text", value: action.value.text, contentType: action.value.contentType, }); } else { - content = asyncValue.fulfilled({ + content = fulfilled({ type: "wasm", value: action.value.text, }); @@ -789,7 +798,7 @@ export function getSourceContent( id: SourceId ): SettledValue | null { const { content } = getResource(state.sources.sources, id); - return asyncValue.asSettled(content); + return asSettled(content); } export function getSelectedSourceId(state: OuterState) { @@ -926,6 +935,38 @@ export function canLoadSource( return actors.length != 0; } +export function isSourceWithMap( + state: OuterState & SourceActorOuterState, + id: SourceId +): boolean { + const source = getSource(state, id); + return source ? !!source.sourceMapURL : false; +} + +export function canPrettyPrintSource( + state: OuterState & SourceActorOuterState, + id: SourceId +): boolean { + const source: SourceWithContent = getSourceWithContent(state, id); + if ( + !source || + isPretty(source) || + isOriginalSource(source) || + (prefs.clientSourceMapsEnabled && isSourceWithMap(state, id)) + ) { + return false; + } + + const sourceContent = + source.content && isFulfilled(source.content) ? source.content.value : null; + + if (!sourceContent || !isJavaScript(source, sourceContent)) { + return false; + } + + return true; +} + export function getBreakpointPositions( state: OuterState ): BreakpointPositionsMap { diff --git a/devtools/client/debugger/src/utils/editor/index.js b/devtools/client/debugger/src/utils/editor/index.js index b7d3065d0cea..7ef510089af5 100644 --- a/devtools/client/debugger/src/utils/editor/index.js +++ b/devtools/client/debugger/src/utils/editor/index.js @@ -11,19 +11,13 @@ export * from "../ui"; export { onMouseOver } from "./token-events"; import { createEditor } from "./create-editor"; -import { shouldPrettyPrint } from "../source"; import { findNext, findPrev } from "./source-search"; import { isWasm, lineToWasmOffset, wasmOffsetToLine } from "../wasm"; import type { AstLocation } from "../../workers/parser"; import type { EditorPosition, EditorRange } from "../editor/types"; -import type { - SearchModifiers, - Source, - SourceContent, - SourceLocation, -} from "../../types"; +import type { SearchModifiers, Source, SourceLocation } from "../../types"; type Editor = Object; let editor: ?Editor; @@ -63,10 +57,6 @@ export function endOperation() { codeMirror.endOperation(); } -export function shouldShowPrettyPrint(source: Source, content: SourceContent) { - return shouldPrettyPrint(source, content); -} - export function traverseResults( e: Event, ctx: any, diff --git a/devtools/client/debugger/src/utils/editor/tests/editor.spec.js b/devtools/client/debugger/src/utils/editor/tests/editor.spec.js index e62fa350b24d..533fe757bae3 100644 --- a/devtools/client/debugger/src/utils/editor/tests/editor.spec.js +++ b/devtools/client/debugger/src/utils/editor/tests/editor.spec.js @@ -5,7 +5,6 @@ // @flow import { - shouldShowPrettyPrint, traverseResults, toEditorLine, toEditorPosition, @@ -22,19 +21,7 @@ import { getCursorLine, } from "../index"; -import { makeMockSource, makeMockSourceAndContent } from "../../test-mockup"; - -describe("shouldShowPrettyPrint", () => { - it("shows pretty print for a source", () => { - const { content, ...source } = makeMockSourceAndContent( - "http://example.com/index.js", - "test-id-123", - "text/javascript", - "some text here" - ); - expect(shouldShowPrettyPrint(source, content)).toEqual(true); - }); -}); +import { makeMockSource } from "../../test-mockup"; describe("traverseResults", () => { const e: any = { stopPropagation: jest.fn(), preventDefault: jest.fn() }; diff --git a/devtools/client/debugger/src/utils/source.js b/devtools/client/debugger/src/utils/source.js index 218361f75487..72d6c3f1d889 100644 --- a/devtools/client/debugger/src/utils/source.js +++ b/devtools/client/debugger/src/utils/source.js @@ -20,7 +20,7 @@ import { renderWasmText } from "./wasm"; import { toEditorLine } from "./editor"; export { isMinified } from "./isMinified"; import { getURL, getFileExtension } from "./sources-tree"; -import { prefs, features } from "./prefs"; +import { features } from "./prefs"; import type { SourceId, @@ -78,23 +78,6 @@ export function shouldBlackbox(source: ?Source) { return true; } -export function shouldPrettyPrint( - source: Source, - content: SourceContent -): boolean { - if ( - !source || - isPretty(source) || - !isJavaScript(source, content) || - isOriginal(source) || - (prefs.clientSourceMapsEnabled && source.sourceMapURL) - ) { - return false; - } - - return true; -} - /** * Returns true if the specified url and/or content type are specific to * javascript files.