summaryrefslogtreecommitdiffstats
path: root/devtools/client/debugger/src/actions/project-text-search.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/debugger/src/actions/project-text-search.js')
-rw-r--r--devtools/client/debugger/src/actions/project-text-search.js136
1 files changed, 136 insertions, 0 deletions
diff --git a/devtools/client/debugger/src/actions/project-text-search.js b/devtools/client/debugger/src/actions/project-text-search.js
new file mode 100644
index 0000000000..327dbccda5
--- /dev/null
+++ b/devtools/client/debugger/src/actions/project-text-search.js
@@ -0,0 +1,136 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
+
+// @flow
+
+/**
+ * Redux actions for the search state
+ * @module actions/search
+ */
+
+import { isFulfilled } from "../utils/async-value";
+import { findSourceMatches } from "../workers/search";
+import {
+ getSource,
+ hasPrettySource,
+ getSourceList,
+ getSourceContent,
+} from "../selectors";
+import { isThirdParty } from "../utils/source";
+import { loadSourceText } from "./sources/loadSourceText";
+import {
+ statusType,
+ getTextSearchOperation,
+ getTextSearchStatus,
+} from "../reducers/project-text-search";
+
+import type { Action, ThunkArgs } from "./types";
+import type { Context, SourceId } from "../types";
+import type {
+ SearchOperation,
+ StatusType,
+} from "../reducers/project-text-search";
+
+export function addSearchQuery(cx: Context, query: string): Action {
+ return { type: "ADD_QUERY", cx, query };
+}
+
+export function addOngoingSearch(
+ cx: Context,
+ ongoingSearch: SearchOperation
+): Action {
+ return { type: "ADD_ONGOING_SEARCH", cx, ongoingSearch };
+}
+
+export function addSearchResult(
+ cx: Context,
+ sourceId: SourceId,
+ filepath: string,
+ matches: Object[]
+): Action {
+ return {
+ type: "ADD_SEARCH_RESULT",
+ cx,
+ result: { sourceId, filepath, matches },
+ };
+}
+
+export function clearSearchResults(cx: Context): Action {
+ return { type: "CLEAR_SEARCH_RESULTS", cx };
+}
+
+export function clearSearch(cx: Context): Action {
+ return { type: "CLEAR_SEARCH", cx };
+}
+
+export function updateSearchStatus(cx: Context, status: StatusType): Action {
+ return { type: "UPDATE_STATUS", cx, status };
+}
+
+export function closeProjectSearch(cx: Context) {
+ return ({ dispatch, getState }: ThunkArgs) => {
+ dispatch(stopOngoingSearch(cx));
+ dispatch({ type: "CLOSE_PROJECT_SEARCH" });
+ };
+}
+
+export function stopOngoingSearch(cx: Context) {
+ return ({ dispatch, getState }: ThunkArgs) => {
+ const state = getState();
+ const ongoingSearch = getTextSearchOperation(state);
+ const status = getTextSearchStatus(state);
+ if (ongoingSearch && status !== statusType.done) {
+ ongoingSearch.cancel();
+ dispatch(updateSearchStatus(cx, statusType.cancelled));
+ }
+ };
+}
+
+export function searchSources(cx: Context, query: string) {
+ let cancelled = false;
+
+ const search = async ({ dispatch, getState }: ThunkArgs) => {
+ dispatch(stopOngoingSearch(cx));
+ await dispatch(addOngoingSearch(cx, search));
+ await dispatch(clearSearchResults(cx));
+ await dispatch(addSearchQuery(cx, query));
+ dispatch(updateSearchStatus(cx, statusType.fetching));
+ const validSources = getSourceList(getState()).filter(
+ source => !hasPrettySource(getState(), source.id) && !isThirdParty(source)
+ );
+ for (const source of validSources) {
+ if (cancelled) {
+ return;
+ }
+ await dispatch(loadSourceText({ cx, source }));
+ await dispatch(searchSource(cx, source.id, query));
+ }
+ dispatch(updateSearchStatus(cx, statusType.done));
+ };
+
+ search.cancel = () => {
+ cancelled = true;
+ };
+
+ return search;
+}
+
+export function searchSource(cx: Context, sourceId: SourceId, query: string) {
+ return async ({ dispatch, getState }: ThunkArgs) => {
+ const source = getSource(getState(), sourceId);
+ if (!source) {
+ return;
+ }
+
+ const content = getSourceContent(getState(), source.id);
+ let matches = [];
+ if (content && isFulfilled(content) && content.value.type === "text") {
+ matches = await findSourceMatches(source.id, content.value, query);
+ }
+ if (!matches.length) {
+ return;
+ }
+ dispatch(addSearchResult(cx, source.id, source.url, matches));
+ };
+}