зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1558303 - Stop using immutable.
Differential Revision: https://phabricator.services.mozilla.com/D34411 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
bbc8c51513
Коммит
8578b45a14
|
@ -61,7 +61,6 @@
|
|||
"devtools-splitter": "^0.0.8",
|
||||
"devtools-utils": "0.0.14",
|
||||
"fuzzaldrin-plus": "^0.6.0",
|
||||
"immutable": "^3.8.2",
|
||||
"lodash": "^4.17.4",
|
||||
"lodash-move": "^1.1.1",
|
||||
"lodash.kebabcase": "^4.1.1",
|
||||
|
@ -72,7 +71,6 @@
|
|||
"react": "16.4.1",
|
||||
"react-aria-components": "^0.0.4",
|
||||
"react-dom": "16.4.1",
|
||||
"react-immutable-proptypes": "^2.1.0",
|
||||
"react-redux": "^5.0.7",
|
||||
"react-transition-group": "^2.2.1",
|
||||
"reselect": "^4.0.0",
|
||||
|
|
|
@ -121,7 +121,7 @@ export function deleteExpression(expression: Expression) {
|
|||
*/
|
||||
export function evaluateExpressions(cx: ThreadContext) {
|
||||
return async function({ dispatch, getState, client }: ThunkArgs) {
|
||||
const expressions = getExpressions(getState()).toJS();
|
||||
const expressions = getExpressions(getState());
|
||||
const inputs = expressions.map(({ input }) => input);
|
||||
const frameId = getSelectedFrameId(getState(), cx.thread);
|
||||
const results = await client.evaluateExpressions(inputs, {
|
||||
|
|
|
@ -126,7 +126,6 @@ export function searchContents(
|
|||
return;
|
||||
}
|
||||
|
||||
const _modifiers = modifiers.toJS();
|
||||
let text;
|
||||
if (selectedContent.type === "wasm") {
|
||||
text = renderWasmText(selectedSource.id, selectedContent).join("\n");
|
||||
|
@ -134,9 +133,9 @@ export function searchContents(
|
|||
text = selectedContent.value;
|
||||
}
|
||||
|
||||
const matches = await getMatches(query, text, _modifiers);
|
||||
const matches = await getMatches(query, text, modifiers);
|
||||
|
||||
const res = find(ctx, query, true, _modifiers, focusFirstResult);
|
||||
const res = find(ctx, query, true, modifiers, focusFirstResult);
|
||||
if (!res) {
|
||||
return;
|
||||
}
|
||||
|
@ -168,9 +167,7 @@ export function searchContentsForHighlight(
|
|||
}
|
||||
|
||||
const ctx = { ed: editor, cm: editor.codeMirror };
|
||||
const _modifiers = modifiers.toJS();
|
||||
|
||||
searchSourceForHighlight(ctx, false, query, true, _modifiers, line, ch);
|
||||
searchSourceForHighlight(ctx, false, query, true, modifiers, line, ch);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -192,7 +189,7 @@ export function traverseResults(cx: Context, rev: boolean, editor: Editor) {
|
|||
|
||||
if (modifiers) {
|
||||
const matchedLocations = matches || [];
|
||||
const findArgs = [ctx, query, true, modifiers.toJS()];
|
||||
const findArgs = [ctx, query, true, modifiers];
|
||||
const results = rev ? findPrev(...findArgs) : findNext(...findArgs);
|
||||
|
||||
if (!results) {
|
||||
|
|
|
@ -403,7 +403,7 @@ describe("pause", () => {
|
|||
|
||||
await dispatch(actions.resumed(resumedPacket()));
|
||||
const expression = selectors.getExpression(getState(), "foo");
|
||||
expect(expression.value).toEqual("YAY");
|
||||
expect(expression && expression.value).toEqual("YAY");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -55,7 +55,7 @@ describe("expressions", () => {
|
|||
const { dispatch, getState, cx } = createStore(mockThreadClient);
|
||||
|
||||
await dispatch(actions.addExpression(cx, "foo"));
|
||||
expect(selectors.getExpressions(getState()).size).toBe(1);
|
||||
expect(selectors.getExpressions(getState())).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("should not add empty expressions", () => {
|
||||
|
@ -63,14 +63,14 @@ describe("expressions", () => {
|
|||
|
||||
dispatch(actions.addExpression(cx, (undefined: any)));
|
||||
dispatch(actions.addExpression(cx, ""));
|
||||
expect(selectors.getExpressions(getState()).size).toBe(0);
|
||||
expect(selectors.getExpressions(getState())).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("should not add invalid expressions", async () => {
|
||||
const { dispatch, getState, cx } = createStore(mockThreadClient);
|
||||
await dispatch(actions.addExpression(cx, "foo#"));
|
||||
const state = getState();
|
||||
expect(selectors.getExpressions(state).size).toBe(0);
|
||||
expect(selectors.getExpressions(state)).toHaveLength(0);
|
||||
expect(selectors.getExpressionError(state)).toBe(true);
|
||||
});
|
||||
|
||||
|
@ -79,9 +79,14 @@ describe("expressions", () => {
|
|||
|
||||
await dispatch(actions.addExpression(cx, "foo"));
|
||||
const expression = selectors.getExpression(getState(), "foo");
|
||||
await dispatch(actions.updateExpression(cx, "bar", expression));
|
||||
if (!expression) {
|
||||
throw new Error("expression must exist");
|
||||
}
|
||||
|
||||
expect(selectors.getExpression(getState(), "bar").input).toBe("bar");
|
||||
await dispatch(actions.updateExpression(cx, "bar", expression));
|
||||
const bar = selectors.getExpression(getState(), "bar");
|
||||
|
||||
expect(bar && bar.input).toBe("bar");
|
||||
});
|
||||
|
||||
it("should not update an expression w/ invalid code", async () => {
|
||||
|
@ -89,6 +94,9 @@ describe("expressions", () => {
|
|||
|
||||
await dispatch(actions.addExpression(cx, "foo"));
|
||||
const expression = selectors.getExpression(getState(), "foo");
|
||||
if (!expression) {
|
||||
throw new Error("expression must exist");
|
||||
}
|
||||
await dispatch(actions.updateExpression(cx, "#bar", expression));
|
||||
expect(selectors.getExpression(getState(), "bar")).toBeUndefined();
|
||||
});
|
||||
|
@ -98,24 +106,35 @@ describe("expressions", () => {
|
|||
|
||||
await dispatch(actions.addExpression(cx, "foo"));
|
||||
await dispatch(actions.addExpression(cx, "bar"));
|
||||
expect(selectors.getExpressions(getState()).size).toBe(2);
|
||||
expect(selectors.getExpressions(getState())).toHaveLength(2);
|
||||
|
||||
const expression = selectors.getExpression(getState(), "foo");
|
||||
|
||||
if (!expression) {
|
||||
throw new Error("expression must exist");
|
||||
}
|
||||
|
||||
const bar = selectors.getExpression(getState(), "bar");
|
||||
dispatch(actions.deleteExpression(expression));
|
||||
expect(selectors.getExpressions(getState()).size).toBe(1);
|
||||
expect(selectors.getExpression(getState(), "bar").input).toBe("bar");
|
||||
expect(selectors.getExpressions(getState())).toHaveLength(1);
|
||||
expect(bar && bar.input).toBe("bar");
|
||||
});
|
||||
|
||||
it("should evaluate expressions global scope", async () => {
|
||||
const { dispatch, getState, cx } = createStore(mockThreadClient);
|
||||
await dispatch(actions.addExpression(cx, "foo"));
|
||||
await dispatch(actions.addExpression(cx, "bar"));
|
||||
expect(selectors.getExpression(getState(), "foo").value).toBe("bla");
|
||||
expect(selectors.getExpression(getState(), "bar").value).toBe("bla");
|
||||
|
||||
let foo = selectors.getExpression(getState(), "foo");
|
||||
let bar = selectors.getExpression(getState(), "bar");
|
||||
expect(foo && foo.value).toBe("bla");
|
||||
expect(bar && bar.value).toBe("bla");
|
||||
|
||||
await dispatch(actions.evaluateExpressions(cx));
|
||||
expect(selectors.getExpression(getState(), "foo").value).toBe("bla");
|
||||
expect(selectors.getExpression(getState(), "bar").value).toBe("bla");
|
||||
foo = selectors.getExpression(getState(), "foo");
|
||||
bar = selectors.getExpression(getState(), "bar");
|
||||
expect(foo && foo.value).toBe("bla");
|
||||
expect(bar && bar.value).toBe("bla");
|
||||
});
|
||||
|
||||
it("should evaluate expressions in specific scope", async () => {
|
||||
|
@ -127,13 +146,16 @@ describe("expressions", () => {
|
|||
await dispatch(actions.addExpression(cx, "foo"));
|
||||
await dispatch(actions.addExpression(cx, "bar"));
|
||||
|
||||
expect(selectors.getExpression(getState(), "foo").value).toBe("boo");
|
||||
expect(selectors.getExpression(getState(), "bar").value).toBe("boo");
|
||||
let foo = selectors.getExpression(getState(), "foo");
|
||||
let bar = selectors.getExpression(getState(), "bar");
|
||||
expect(foo && foo.value).toBe("boo");
|
||||
expect(bar && bar.value).toBe("boo");
|
||||
|
||||
await dispatch(actions.evaluateExpressions(cx));
|
||||
|
||||
expect(selectors.getExpression(getState(), "foo").value).toBe("boo");
|
||||
expect(selectors.getExpression(getState(), "bar").value).toBe("boo");
|
||||
foo = selectors.getExpression(getState(), "foo");
|
||||
bar = selectors.getExpression(getState(), "bar");
|
||||
expect(foo && foo.value).toBe("boo");
|
||||
expect(bar && bar.value).toBe("boo");
|
||||
});
|
||||
|
||||
it("should get the autocomplete matches for the input", async () => {
|
||||
|
|
|
@ -45,10 +45,10 @@ describe("file text search", () => {
|
|||
it("should toggle a file search modifier", () => {
|
||||
const { dispatch, getState, cx } = createStore();
|
||||
let fileSearchModState = getFileSearchModifiers(getState());
|
||||
expect(fileSearchModState.get("caseSensitive")).toBe(false);
|
||||
expect(fileSearchModState.caseSensitive).toBe(false);
|
||||
dispatch(actions.toggleFileSearchModifier(cx, "caseSensitive"));
|
||||
fileSearchModState = getFileSearchModifiers(getState());
|
||||
expect(fileSearchModState.get("caseSensitive")).toBe(true);
|
||||
expect(fileSearchModState.caseSensitive).toBe(true);
|
||||
});
|
||||
|
||||
it("should toggle a file search query cleaning", () => {
|
||||
|
|
|
@ -4,12 +4,7 @@
|
|||
|
||||
// @flow
|
||||
|
||||
import type {
|
||||
Source,
|
||||
PartialRange,
|
||||
SourceLocation,
|
||||
Context,
|
||||
} from "../../types";
|
||||
import type { Source, Range, SourceLocation, Context } from "../../types";
|
||||
|
||||
import type {
|
||||
ActiveSearchType,
|
||||
|
@ -81,5 +76,5 @@ export type UIAction =
|
|||
|}
|
||||
| {|
|
||||
+type: "SET_VIEWPORT",
|
||||
+viewport: PartialRange,
|
||||
+viewport: Range,
|
||||
|};
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
getPaneCollapse,
|
||||
getQuickOpenEnabled,
|
||||
getSource,
|
||||
getSourceContent,
|
||||
startsWithThreadActor,
|
||||
getFileSearchQuery,
|
||||
getProjectDirectoryRoot,
|
||||
|
@ -17,8 +18,10 @@ import { selectSource } from "../actions/sources/select";
|
|||
import type { ThunkArgs, panelPositionType } from "./types";
|
||||
import { getEditor, getLocationsInViewport } from "../utils/editor";
|
||||
import { searchContents } from "./file-search";
|
||||
import { copyToTheClipboard } from "../utils/clipboard";
|
||||
import { isFulfilled } from "../utils/async-value";
|
||||
|
||||
import type { SourceLocation, Context } from "../types";
|
||||
import type { SourceLocation, Context, Source } from "../types";
|
||||
import type {
|
||||
ActiveSearchType,
|
||||
OrientationType,
|
||||
|
@ -219,3 +222,12 @@ export function updateViewport() {
|
|||
export function setOrientation(orientation: OrientationType) {
|
||||
return { type: "SET_ORIENTATION", orientation };
|
||||
}
|
||||
|
||||
export function copyToClipboard(source: Source) {
|
||||
return ({ dispatch, getState }: ThunkArgs) => {
|
||||
const content = getSourceContent(getState(), source.id);
|
||||
if (content && isFulfilled(content) && content.value.type === "text") {
|
||||
copyToTheClipboard(content.value.value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -251,7 +251,7 @@ class SearchBar extends Component<Props, State> {
|
|||
|
||||
function SearchModBtn({ modVal, className, svgName, tooltip }) {
|
||||
const preppedClass = classnames(className, {
|
||||
active: modifiers && modifiers.get(modVal),
|
||||
active: modifiers && modifiers[modVal],
|
||||
});
|
||||
return (
|
||||
<button
|
||||
|
|
|
@ -11,8 +11,8 @@ import { showMenu, buildMenu } from "devtools-contextmenu";
|
|||
|
||||
import SourceIcon from "../shared/SourceIcon";
|
||||
import { CloseButton } from "../shared/Button";
|
||||
import { copyToTheClipboard } from "../../utils/clipboard";
|
||||
|
||||
import type { List } from "immutable";
|
||||
import type { Source, Context } from "../../types";
|
||||
|
||||
import actions from "../../actions";
|
||||
|
@ -26,7 +26,6 @@ import {
|
|||
isPretty,
|
||||
shouldBlackbox,
|
||||
} from "../../utils/source";
|
||||
import { copyToTheClipboard } from "../../utils/clipboard";
|
||||
import { getTabMenuItems } from "../../utils/tabs";
|
||||
|
||||
import {
|
||||
|
@ -40,11 +39,9 @@ import type { ActiveSearchType } from "../../selectors";
|
|||
|
||||
import classnames from "classnames";
|
||||
|
||||
type SourcesList = List<Source>;
|
||||
|
||||
type Props = {
|
||||
cx: Context,
|
||||
tabSources: SourcesList,
|
||||
tabSources: Source[],
|
||||
selectedSource: Source,
|
||||
source: Source,
|
||||
activeSearch: ActiveSearchType,
|
||||
|
@ -52,6 +49,7 @@ type Props = {
|
|||
selectSource: typeof actions.selectSource,
|
||||
closeTab: typeof actions.closeTab,
|
||||
closeTabs: typeof actions.closeTabs,
|
||||
copyToClipboard: typeof actions.copyToClipboard,
|
||||
togglePrettyPrint: typeof actions.togglePrettyPrint,
|
||||
showSource: typeof actions.showSource,
|
||||
toggleBlackBox: typeof actions.toggleBlackBox,
|
||||
|
@ -68,6 +66,7 @@ class Tab extends PureComponent<Props> {
|
|||
cx,
|
||||
closeTab,
|
||||
closeTabs,
|
||||
copyToClipboard,
|
||||
tabSources,
|
||||
showSource,
|
||||
toggleBlackBox,
|
||||
|
@ -124,7 +123,7 @@ class Tab extends PureComponent<Props> {
|
|||
item: {
|
||||
...tabMenuItems.copyToClipboard,
|
||||
disabled: selectedSource.id !== tab,
|
||||
click: () => copyToTheClipboard(sourceTab.text),
|
||||
click: () => copyToClipboard(sourceTab),
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -250,6 +249,7 @@ export default connect(
|
|||
mapStateToProps,
|
||||
{
|
||||
selectSource: actions.selectSource,
|
||||
copyToClipboard: actions.copyToClipboard,
|
||||
closeTab: actions.closeTab,
|
||||
closeTabs: actions.closeTabs,
|
||||
togglePrettyPrint: actions.togglePrettyPrint,
|
||||
|
|
|
@ -79,7 +79,7 @@ class Expressions extends Component<Props, State> {
|
|||
componentDidMount() {
|
||||
const { cx, expressions, evaluateExpressions, showInput } = this.props;
|
||||
|
||||
if (expressions.size > 0) {
|
||||
if (expressions.length > 0) {
|
||||
evaluateExpressions(cx);
|
||||
}
|
||||
|
||||
|
@ -377,7 +377,7 @@ class Expressions extends Component<Props, State> {
|
|||
return (
|
||||
<ul className="pane expressions-list">
|
||||
{expressions.map(this.renderExpression)}
|
||||
{(showInput || !expressions.size) && this.renderNewExpressionInput()}
|
||||
{(showInput || !expressions.length) && this.renderNewExpressionInput()}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import Expressions from "../Expressions";
|
|||
|
||||
function generateDefaults(overrides) {
|
||||
return {
|
||||
evaluateExpressions: async () => {},
|
||||
expressions: [
|
||||
{
|
||||
input: "expression1",
|
||||
|
|
|
@ -88,33 +88,6 @@ exports[`Expressions should always have unique keys 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li
|
||||
className="expression-input-container"
|
||||
>
|
||||
<form
|
||||
className="expression-input-form"
|
||||
onSubmit={[Function]}
|
||||
>
|
||||
<input
|
||||
className="input-expression"
|
||||
onBlur={[Function]}
|
||||
onChange={[Function]}
|
||||
onFocus={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
placeholder="Add watch expression"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<input
|
||||
style={
|
||||
Object {
|
||||
"display": "none",
|
||||
}
|
||||
}
|
||||
type="submit"
|
||||
/>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
`;
|
||||
|
||||
|
@ -206,32 +179,5 @@ exports[`Expressions should render 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li
|
||||
className="expression-input-container"
|
||||
>
|
||||
<form
|
||||
className="expression-input-form"
|
||||
onSubmit={[Function]}
|
||||
>
|
||||
<input
|
||||
className="input-expression"
|
||||
onBlur={[Function]}
|
||||
onChange={[Function]}
|
||||
onFocus={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
placeholder="Add watch expression"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<input
|
||||
style={
|
||||
Object {
|
||||
"display": "none",
|
||||
}
|
||||
}
|
||||
type="submit"
|
||||
/>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
`;
|
||||
|
|
|
@ -9,8 +9,6 @@
|
|||
* @module reducers/expressions
|
||||
*/
|
||||
|
||||
import makeRecord from "../utils/makeRecord";
|
||||
import { List, Map } from "immutable";
|
||||
import { omit, zip } from "lodash";
|
||||
|
||||
import { createSelector } from "reselect";
|
||||
|
@ -19,30 +17,30 @@ import { prefs } from "../utils/prefs";
|
|||
import type { Expression } from "../types";
|
||||
import type { Selector, State } from "../reducers/types";
|
||||
import type { Action } from "../actions/types";
|
||||
import type { Record } from "../utils/makeRecord";
|
||||
|
||||
type AutocompleteMatches = { [string]: string[] };
|
||||
export type ExpressionState = {
|
||||
expressions: List<Expression>,
|
||||
expressions: Expression[],
|
||||
expressionError: boolean,
|
||||
autocompleteMatches: Map<string, List<string>>,
|
||||
autocompleteMatches: AutocompleteMatches,
|
||||
currentAutocompleteInput: string | null,
|
||||
};
|
||||
|
||||
export const createExpressionState: () => Record<ExpressionState> = makeRecord({
|
||||
expressions: List(restoreExpressions()),
|
||||
export const createExpressionState = () => ({
|
||||
expressions: restoreExpressions(),
|
||||
expressionError: false,
|
||||
autocompleteMatches: Map({}),
|
||||
autocompleteMatches: {},
|
||||
currentAutocompleteInput: null,
|
||||
});
|
||||
|
||||
function update(
|
||||
state: Record<ExpressionState> = createExpressionState(),
|
||||
state: ExpressionState = createExpressionState(),
|
||||
action: Action
|
||||
): Record<ExpressionState> {
|
||||
): ExpressionState {
|
||||
switch (action.type) {
|
||||
case "ADD_EXPRESSION":
|
||||
if (action.expressionError) {
|
||||
return state.set("expressionError", !!action.expressionError);
|
||||
return { ...state, expressionError: !!action.expressionError };
|
||||
}
|
||||
return appendExpressionToList(state, {
|
||||
input: action.input,
|
||||
|
@ -52,11 +50,13 @@ function update(
|
|||
|
||||
case "UPDATE_EXPRESSION":
|
||||
const key = action.expression.input;
|
||||
return updateExpressionInList(state, key, {
|
||||
const newState = updateExpressionInList(state, key, {
|
||||
input: action.input,
|
||||
value: null,
|
||||
updating: true,
|
||||
}).set("expressionError", !!action.expressionError);
|
||||
});
|
||||
|
||||
return { ...newState, expressionError: !!action.expressionError };
|
||||
|
||||
case "EVALUATE_EXPRESSION":
|
||||
return updateExpressionInList(state, action.input, {
|
||||
|
@ -69,8 +69,8 @@ function update(
|
|||
const { inputs, results } = action;
|
||||
|
||||
return zip(inputs, results).reduce(
|
||||
(newState, [input, result]) =>
|
||||
updateExpressionInList(newState, input, {
|
||||
(_state, [input, result]) =>
|
||||
updateExpressionInList(_state, input, {
|
||||
input: input,
|
||||
value: result,
|
||||
updating: false,
|
||||
|
@ -82,19 +82,26 @@ function update(
|
|||
return deleteExpression(state, action.input);
|
||||
|
||||
case "CLEAR_EXPRESSION_ERROR":
|
||||
return state.set("expressionError", false);
|
||||
return { ...state, expressionError: false };
|
||||
|
||||
case "AUTOCOMPLETE":
|
||||
const { matchProp, matches } = action.result;
|
||||
|
||||
return state
|
||||
.updateIn(["autocompleteMatches", matchProp], list => matches)
|
||||
.set("currentAutocompleteInput", matchProp);
|
||||
return {
|
||||
...state,
|
||||
currentAutocompleteInput: matchProp,
|
||||
autocompleteMatches: {
|
||||
...state.autocompleteMatches,
|
||||
[matchProp]: matches,
|
||||
},
|
||||
};
|
||||
|
||||
case "CLEAR_AUTOCOMPLETE":
|
||||
return state
|
||||
.updateIn(["autocompleteMatches", ""], list => [])
|
||||
.set("currentAutocompleteInput", "");
|
||||
return {
|
||||
...state,
|
||||
autocompleteMatches: {},
|
||||
currentAutocompleteInput: "",
|
||||
};
|
||||
}
|
||||
|
||||
return state;
|
||||
|
@ -103,58 +110,54 @@ function update(
|
|||
function restoreExpressions() {
|
||||
const exprs = prefs.expressions;
|
||||
if (exprs.length == 0) {
|
||||
return;
|
||||
return [];
|
||||
}
|
||||
|
||||
return exprs;
|
||||
}
|
||||
|
||||
function storeExpressions({ expressions }) {
|
||||
prefs.expressions = expressions
|
||||
.map(expression => omit(expression, "value"))
|
||||
.toJS();
|
||||
prefs.expressions = expressions.map(expression => omit(expression, "value"));
|
||||
}
|
||||
|
||||
function appendExpressionToList(state: Record<ExpressionState>, value: any) {
|
||||
const newState = state.update("expressions", () => {
|
||||
return state.expressions.push(value);
|
||||
});
|
||||
function appendExpressionToList(state: ExpressionState, value: any) {
|
||||
const newState = { ...state, expressions: [...state.expressions, value] };
|
||||
|
||||
storeExpressions(newState);
|
||||
return newState;
|
||||
}
|
||||
|
||||
function updateExpressionInList(
|
||||
state: Record<ExpressionState>,
|
||||
state: ExpressionState,
|
||||
key: string,
|
||||
value: any
|
||||
) {
|
||||
const newState = state.update("expressions", () => {
|
||||
const list = state.expressions;
|
||||
const index = list.findIndex(e => e.input == key);
|
||||
return list.update(index, () => value);
|
||||
});
|
||||
const list = [...state.expressions];
|
||||
const index = list.findIndex(e => e.input == key);
|
||||
list[index] = value;
|
||||
|
||||
const newState = { ...state, expressions: list };
|
||||
storeExpressions(newState);
|
||||
return newState;
|
||||
}
|
||||
|
||||
function deleteExpression(state: Record<ExpressionState>, input: string) {
|
||||
const index = state.expressions.findIndex(e => e.input == input);
|
||||
const newState = state.deleteIn(["expressions", index]);
|
||||
function deleteExpression(state: ExpressionState, input: string) {
|
||||
const list = [...state.expressions];
|
||||
const index = list.findIndex(e => e.input == input);
|
||||
list.splice(index, 1);
|
||||
const newState = { ...state, expressions: list };
|
||||
storeExpressions(newState);
|
||||
return newState;
|
||||
}
|
||||
|
||||
const getExpressionsWrapper = state => state.expressions;
|
||||
|
||||
export const getExpressions: Selector<List<Expression>> = createSelector(
|
||||
export const getExpressions: Selector<Array<Expression>> = createSelector(
|
||||
getExpressionsWrapper,
|
||||
expressions => expressions.expressions
|
||||
);
|
||||
|
||||
export const getAutocompleteMatches: Selector<
|
||||
Map<string, List<string>>
|
||||
> = createSelector(
|
||||
export const getAutocompleteMatches: Selector<AutocompleteMatches> = createSelector(
|
||||
getExpressionsWrapper,
|
||||
expressions => expressions.autocompleteMatches
|
||||
);
|
||||
|
@ -164,8 +167,10 @@ export function getExpression(state: State, input: string) {
|
|||
}
|
||||
|
||||
export function getAutocompleteMatchset(state: State) {
|
||||
const input = state.expressions.get("currentAutocompleteInput");
|
||||
return getAutocompleteMatches(state).get(input);
|
||||
const input = state.expressions.currentAutocompleteInput;
|
||||
if (input) {
|
||||
return getAutocompleteMatches(state)[input];
|
||||
}
|
||||
}
|
||||
|
||||
export const getExpressionError: Selector<boolean> = createSelector(
|
||||
|
|
|
@ -9,17 +9,15 @@
|
|||
* @module reducers/fileSearch
|
||||
*/
|
||||
|
||||
import makeRecord from "../utils/makeRecord";
|
||||
import { prefs } from "../utils/prefs";
|
||||
|
||||
import type { Action } from "../actions/types";
|
||||
import type { Record } from "../utils/makeRecord";
|
||||
|
||||
export type Modifiers = Record<{
|
||||
export type Modifiers = {
|
||||
caseSensitive: boolean,
|
||||
wholeWord: boolean,
|
||||
regexMatch: boolean,
|
||||
}>;
|
||||
};
|
||||
|
||||
export type MatchedLocations = {
|
||||
line: number,
|
||||
|
@ -46,27 +44,27 @@ const emptySearchResults = Object.freeze({
|
|||
count: 0,
|
||||
});
|
||||
|
||||
export const createFileSearchState: () => Record<FileSearchState> = makeRecord({
|
||||
export const createFileSearchState = () => ({
|
||||
query: "",
|
||||
searchResults: emptySearchResults,
|
||||
modifiers: makeRecord({
|
||||
modifiers: {
|
||||
caseSensitive: prefs.fileSearchCaseSensitive,
|
||||
wholeWord: prefs.fileSearchWholeWord,
|
||||
regexMatch: prefs.fileSearchRegexMatch,
|
||||
})(),
|
||||
},
|
||||
});
|
||||
|
||||
function update(
|
||||
state: Record<FileSearchState> = createFileSearchState(),
|
||||
state: FileSearchState = createFileSearchState(),
|
||||
action: Action
|
||||
): Record<FileSearchState> {
|
||||
): FileSearchState {
|
||||
switch (action.type) {
|
||||
case "UPDATE_FILE_SEARCH_QUERY": {
|
||||
return state.set("query", action.query);
|
||||
return { ...state, query: action.query };
|
||||
}
|
||||
|
||||
case "UPDATE_SEARCH_RESULTS": {
|
||||
return state.set("searchResults", action.results);
|
||||
return { ...state, searchResults: action.results };
|
||||
}
|
||||
|
||||
case "TOGGLE_FILE_SEARCH_MODIFIER": {
|
||||
|
@ -84,11 +82,14 @@ function update(
|
|||
prefs.fileSearchRegexMatch = actionVal;
|
||||
}
|
||||
|
||||
return state.setIn(["modifiers", action.modifier], actionVal);
|
||||
return {
|
||||
...state,
|
||||
modifiers: { ...state.modifiers, [action.modifier]: actionVal },
|
||||
};
|
||||
}
|
||||
|
||||
case "NAVIGATE": {
|
||||
return state.set("query", "").set("searchResults", emptySearchResults);
|
||||
return { ...state, query: "", searchResults: emptySearchResults };
|
||||
}
|
||||
|
||||
default: {
|
||||
|
@ -99,7 +100,7 @@ function update(
|
|||
|
||||
// NOTE: we'd like to have the app state fully typed
|
||||
// https://github.com/firefox-devtools/debugger/blob/master/src/reducers/sources.js#L179-L185
|
||||
type OuterState = { fileSearch: Record<FileSearchState> };
|
||||
type OuterState = { fileSearch: FileSearchState };
|
||||
|
||||
export function getFileSearchQuery(state: OuterState): string {
|
||||
return state.fileSearch.query;
|
||||
|
|
|
@ -9,10 +9,8 @@
|
|||
* @module reducers/quick-open
|
||||
*/
|
||||
|
||||
import makeRecord from "../utils/makeRecord";
|
||||
import { parseQuickOpenQuery } from "../utils/quick-open";
|
||||
import type { Action } from "../actions/types";
|
||||
import type { Record } from "../utils/makeRecord";
|
||||
|
||||
export type QuickOpenType = "sources" | "functions" | "goto" | "gotoSource";
|
||||
|
||||
|
@ -22,50 +20,52 @@ export type QuickOpenState = {
|
|||
searchType: QuickOpenType,
|
||||
};
|
||||
|
||||
export const createQuickOpenState: () => Record<QuickOpenState> = makeRecord({
|
||||
export const createQuickOpenState = (): QuickOpenState => ({
|
||||
enabled: false,
|
||||
query: "",
|
||||
searchType: "sources",
|
||||
});
|
||||
|
||||
export default function update(
|
||||
state: Record<QuickOpenState> = createQuickOpenState(),
|
||||
state: QuickOpenState = createQuickOpenState(),
|
||||
action: Action
|
||||
): Record<QuickOpenState> {
|
||||
): QuickOpenState {
|
||||
switch (action.type) {
|
||||
case "OPEN_QUICK_OPEN":
|
||||
if (action.query != null) {
|
||||
return state.merge({
|
||||
return {
|
||||
...state,
|
||||
enabled: true,
|
||||
query: action.query,
|
||||
searchType: parseQuickOpenQuery(action.query),
|
||||
});
|
||||
};
|
||||
}
|
||||
return state.set("enabled", true);
|
||||
return { ...state, enabled: true };
|
||||
case "CLOSE_QUICK_OPEN":
|
||||
return createQuickOpenState();
|
||||
case "SET_QUICK_OPEN_QUERY":
|
||||
return state.merge({
|
||||
return {
|
||||
...state,
|
||||
query: action.query,
|
||||
searchType: parseQuickOpenQuery(action.query),
|
||||
});
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
type OuterState = {
|
||||
quickOpen: Record<QuickOpenState>,
|
||||
quickOpen: QuickOpenState,
|
||||
};
|
||||
|
||||
export function getQuickOpenEnabled(state: OuterState): boolean {
|
||||
return state.quickOpen.get("enabled");
|
||||
return state.quickOpen.enabled;
|
||||
}
|
||||
|
||||
export function getQuickOpenQuery(state: OuterState) {
|
||||
return state.quickOpen.get("query");
|
||||
return state.quickOpen.query;
|
||||
}
|
||||
|
||||
export function getQuickOpenType(state: OuterState): QuickOpenType {
|
||||
return state.quickOpen.get("searchType");
|
||||
return state.quickOpen.searchType;
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ export type State = {
|
|||
expressions: Record<ExpressionState>,
|
||||
eventListenerBreakpoints: EventListenersState,
|
||||
debuggee: DebuggeeState,
|
||||
fileSearch: Record<FileSearchState>,
|
||||
fileSearch: FileSearchState,
|
||||
pause: PauseState,
|
||||
preview: PreviewState,
|
||||
pendingBreakpoints: PendingBreakpointsState,
|
||||
|
@ -40,8 +40,8 @@ export type State = {
|
|||
sources: SourcesState,
|
||||
sourceActors: SourceActorsState,
|
||||
tabs: TabList,
|
||||
ui: Record<UIState>,
|
||||
quickOpen: Record<QuickOpenState>,
|
||||
ui: UIState,
|
||||
quickOpen: QuickOpenState,
|
||||
};
|
||||
|
||||
export type Selector<T> = State => T;
|
||||
|
|
|
@ -9,13 +9,11 @@
|
|||
* @module reducers/ui
|
||||
*/
|
||||
|
||||
import makeRecord from "../utils/makeRecord";
|
||||
import { prefs } from "../utils/prefs";
|
||||
|
||||
import type { Source, PartialRange, SourceLocation } from "../types";
|
||||
import type { Source, Range, SourceLocation } from "../types";
|
||||
|
||||
import type { Action, panelPositionType } from "../actions/types";
|
||||
import type { Record } from "../utils/makeRecord";
|
||||
|
||||
export type ActiveSearchType = "project" | "file";
|
||||
|
||||
|
@ -23,8 +21,6 @@ export type OrientationType = "horizontal" | "vertical";
|
|||
|
||||
export type SelectedPrimaryPaneTabType = "sources" | "outline";
|
||||
|
||||
type Viewport = PartialRange;
|
||||
|
||||
export type UIState = {
|
||||
selectedPrimaryPaneTab: SelectedPrimaryPaneTabType,
|
||||
activeSearch: ?ActiveSearchType,
|
||||
|
@ -33,7 +29,7 @@ export type UIState = {
|
|||
endPanelCollapsed: boolean,
|
||||
frameworkGroupingOn: boolean,
|
||||
orientation: OrientationType,
|
||||
viewport: ?Viewport,
|
||||
viewport: ?Range,
|
||||
highlightedLineRange?: {
|
||||
start?: number,
|
||||
end?: number,
|
||||
|
@ -43,7 +39,7 @@ export type UIState = {
|
|||
isLogPoint: boolean,
|
||||
};
|
||||
|
||||
export const createUIState: () => Record<UIState> = makeRecord({
|
||||
export const createUIState = (): UIState => ({
|
||||
selectedPrimaryPaneTab: "sources",
|
||||
activeSearch: null,
|
||||
shownSource: null,
|
||||
|
@ -57,36 +53,33 @@ export const createUIState: () => Record<UIState> = makeRecord({
|
|||
viewport: null,
|
||||
});
|
||||
|
||||
function update(
|
||||
state: Record<UIState> = createUIState(),
|
||||
action: Action
|
||||
): Record<UIState> {
|
||||
function update(state: UIState = createUIState(), action: Action): UIState {
|
||||
switch (action.type) {
|
||||
case "TOGGLE_ACTIVE_SEARCH": {
|
||||
return state.set("activeSearch", action.value);
|
||||
return { ...state, activeSearch: action.value };
|
||||
}
|
||||
|
||||
case "TOGGLE_FRAMEWORK_GROUPING": {
|
||||
prefs.frameworkGroupingOn = action.value;
|
||||
return state.set("frameworkGroupingOn", action.value);
|
||||
return { ...state, frameworkGroupingOn: action.value };
|
||||
}
|
||||
|
||||
case "SET_ORIENTATION": {
|
||||
return state.set("orientation", action.orientation);
|
||||
return { ...state, orientation: action.orientation };
|
||||
}
|
||||
|
||||
case "SHOW_SOURCE": {
|
||||
return state.set("shownSource", action.source);
|
||||
return { ...state, shownSource: action.source };
|
||||
}
|
||||
|
||||
case "TOGGLE_PANE": {
|
||||
if (action.position == "start") {
|
||||
prefs.startPanelCollapsed = action.paneCollapsed;
|
||||
return state.set("startPanelCollapsed", action.paneCollapsed);
|
||||
return { ...state, startPanelCollapsed: action.paneCollapsed };
|
||||
}
|
||||
|
||||
prefs.endPanelCollapsed = action.paneCollapsed;
|
||||
return state.set("endPanelCollapsed", action.paneCollapsed);
|
||||
return { ...state, endPanelCollapsed: action.paneCollapsed };
|
||||
}
|
||||
|
||||
case "HIGHLIGHT_LINES":
|
||||
|
@ -97,36 +90,38 @@ function update(
|
|||
lineRange = { start, end, sourceId };
|
||||
}
|
||||
|
||||
return state.set("highlightedLineRange", lineRange);
|
||||
return { ...state, highlightedLineRange: lineRange };
|
||||
|
||||
case "CLOSE_QUICK_OPEN":
|
||||
case "CLEAR_HIGHLIGHT_LINES":
|
||||
return state.set("highlightedLineRange", {});
|
||||
return { ...state, highlightedLineRange: {} };
|
||||
|
||||
case "OPEN_CONDITIONAL_PANEL":
|
||||
return state
|
||||
.set("conditionalPanelLocation", action.location)
|
||||
.set("isLogPoint", action.log);
|
||||
return {
|
||||
...state,
|
||||
conditionalPanelLocation: action.location,
|
||||
isLogPoint: action.log,
|
||||
};
|
||||
|
||||
case "CLOSE_CONDITIONAL_PANEL":
|
||||
return state.set("conditionalPanelLocation", null);
|
||||
return { ...state, conditionalPanelLocation: null };
|
||||
|
||||
case "SET_PRIMARY_PANE_TAB":
|
||||
return state.set("selectedPrimaryPaneTab", action.tabName);
|
||||
return { ...state, selectedPrimaryPaneTab: action.tabName };
|
||||
|
||||
case "CLOSE_PROJECT_SEARCH": {
|
||||
if (state.get("activeSearch") === "project") {
|
||||
return state.set("activeSearch", null);
|
||||
if (state.activeSearch === "project") {
|
||||
return { ...state, activeSearch: null };
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
case "SET_VIEWPORT": {
|
||||
return state.set("viewport", action.viewport);
|
||||
return { ...state, viewport: action.viewport };
|
||||
}
|
||||
|
||||
case "NAVIGATE": {
|
||||
return state.set("activeSearch", null).set("highlightedLineRange", {});
|
||||
return { ...state, activeSearch: null, highlightedLineRange: {} };
|
||||
}
|
||||
|
||||
default: {
|
||||
|
@ -137,24 +132,24 @@ function update(
|
|||
|
||||
// NOTE: we'd like to have the app state fully typed
|
||||
// https://github.com/firefox-devtools/debugger/blob/master/src/reducers/sources.js#L179-L185
|
||||
type OuterState = { ui: Record<UIState> };
|
||||
type OuterState = { ui: UIState };
|
||||
|
||||
export function getSelectedPrimaryPaneTab(
|
||||
state: OuterState
|
||||
): SelectedPrimaryPaneTabType {
|
||||
return state.ui.get("selectedPrimaryPaneTab");
|
||||
return state.ui.selectedPrimaryPaneTab;
|
||||
}
|
||||
|
||||
export function getActiveSearch(state: OuterState): ActiveSearchType {
|
||||
return state.ui.get("activeSearch");
|
||||
export function getActiveSearch(state: OuterState): ?ActiveSearchType {
|
||||
return state.ui.activeSearch;
|
||||
}
|
||||
|
||||
export function getFrameworkGroupingState(state: OuterState): boolean {
|
||||
return state.ui.get("frameworkGroupingOn");
|
||||
return state.ui.frameworkGroupingOn;
|
||||
}
|
||||
|
||||
export function getShownSource(state: OuterState): Source {
|
||||
return state.ui.get("shownSource");
|
||||
export function getShownSource(state: OuterState): ?Source {
|
||||
return state.ui.shownSource;
|
||||
}
|
||||
|
||||
export function getPaneCollapse(
|
||||
|
@ -162,32 +157,32 @@ export function getPaneCollapse(
|
|||
position: panelPositionType
|
||||
): boolean {
|
||||
if (position == "start") {
|
||||
return state.ui.get("startPanelCollapsed");
|
||||
return state.ui.startPanelCollapsed;
|
||||
}
|
||||
|
||||
return state.ui.get("endPanelCollapsed");
|
||||
return state.ui.endPanelCollapsed;
|
||||
}
|
||||
|
||||
export function getHighlightedLineRange(state: OuterState) {
|
||||
return state.ui.get("highlightedLineRange");
|
||||
return state.ui.highlightedLineRange;
|
||||
}
|
||||
|
||||
export function getConditionalPanelLocation(
|
||||
state: OuterState
|
||||
): null | SourceLocation {
|
||||
return state.ui.get("conditionalPanelLocation");
|
||||
return state.ui.conditionalPanelLocation;
|
||||
}
|
||||
|
||||
export function getLogPointStatus(state: OuterState): boolean {
|
||||
return state.ui.get("isLogPoint");
|
||||
return state.ui.isLogPoint;
|
||||
}
|
||||
|
||||
export function getOrientation(state: OuterState): OrientationType {
|
||||
return state.ui.get("orientation");
|
||||
return state.ui.orientation;
|
||||
}
|
||||
|
||||
export function getViewport(state: OuterState) {
|
||||
return state.ui.get("viewport");
|
||||
return state.ui.viewport;
|
||||
}
|
||||
|
||||
export default update;
|
||||
|
|
|
@ -147,7 +147,7 @@ function convertToList(
|
|||
export function getColumnBreakpoints(
|
||||
positions: ?BreakpointPositions,
|
||||
breakpoints: ?(Breakpoint[]),
|
||||
viewport: Range,
|
||||
viewport: ?Range,
|
||||
selectedSourceWithContent: ?SourceWithContent
|
||||
) {
|
||||
if (!positions || !selectedSourceWithContent) {
|
||||
|
|
|
@ -97,6 +97,7 @@ beforeEach(async () => {
|
|||
clearHistory();
|
||||
clearDocuments();
|
||||
prefs.projectDirectoryRoot = "";
|
||||
prefs.expressions = [];
|
||||
|
||||
// Ensures window.dbg is there to track telemetry
|
||||
setupHelper({ selectors: {} });
|
||||
|
|
Загрузка…
Ссылка в новой задаче