Path: blob/master/src/packages/frontend/editors/slate/search/replace-matches.ts
1700 views
/*1* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.2* License: MS-RSL – see LICENSE.md for details3*/45import { Editor, Element, Range, Transforms } from "slate";6import { ReactEditor } from "../slate-react";7import { selectNextMatch } from "./find-matches";8import { nextMatch } from "./search-control";9import { alert_message } from "@cocalc/frontend/alerts";1011function lowestNode(editor: Editor) {12for (const [node] of Editor.nodes(editor, { mode: "lowest" })) {13return node;14}15}1617export function replaceOne(18editor: ReactEditor,19decorate,20replace: string,21noScroll: boolean = false22): boolean {23// collapse selection to the starting edge24if (editor.selection) {25const edges = Range.edges(editor.selection);26Transforms.setSelection(editor, { focus: edges[0], anchor: edges[0] });27}28// find next match29if (selectNextMatch(editor, decorate)) {30const node = lowestNode(editor);31if (node != null) {32if (!(Element.isElement(node) && Editor.isVoid(editor, node))) {33Transforms.insertText(editor, replace);34// Important -- note that insertText puts the focus **after**35// the inserted text. It's important to keep this in mind so that36// the result of replace=search string isn't to make something37// that we immediately replace again thus blowing up the document!38// Make sure to preserve this invariant when implementing this for39// voids.40} else {41// TODO: need to handle void elements differently via a plugin mechanism.42alert_message({43type: "info",44message:45"Replacing nodes of this type not yet implemented. Please use source view.",46});47// At least move to next one no matter what.48if (noScroll) {49selectNextMatch(editor, decorate);50}51}52}53if (!noScroll) {54// Now select and focus whatever is next after what we just55// replaced, in preparation for doing the *next* replace.56nextMatch(editor, decorate);57}58return true;59}60return false;61}6263export function replaceAll(64editor: ReactEditor,65decorate,66replace: string67): void {68// Keep replacing until nothing left to replace. However, we also keep69// of focus points after doing selection so that if for some crazy reason70// this would loop around forever -- e.g., a replace doesn't work properly,71// or maybe the goal of the replace is to add a copy of what is being searched72// for into the document -- in that case, we immediately bail.73const pastSelections = new Set<string>([]);74while (replaceOne(editor, decorate, replace, true)) {75const cur = JSON.stringify(editor.selection?.focus ?? {});76if (pastSelections.has(cur)) return;77pastSelections.add(cur);78}79}808182