From 57814f75222a1e4864eca741c62223d9de2e2bc4 Mon Sep 17 00:00:00 2001 From: filip mertens Date: Mon, 21 Feb 2022 13:12:06 +0100 Subject: [PATCH] regex support --- .../search/src/lib/components/Find.tsx | 33 ++++++- .../search/src/lib/components/Search.tsx | 2 +- .../lib/components/results/ResultFileName.tsx | 23 +++-- .../lib/components/results/ResultSummary.tsx | 6 +- .../lib/components/results/SearchHelper.ts | 3 + .../search/src/lib/context/context.tsx | 92 +++++++++++++------ .../search/src/lib/reducers/Reducer.ts | 6 ++ libs/remix-ui/search/src/lib/search.css | 7 ++ libs/remix-ui/search/src/lib/types/index.ts | 2 + 9 files changed, 129 insertions(+), 45 deletions(-) diff --git a/libs/remix-ui/search/src/lib/components/Find.tsx b/libs/remix-ui/search/src/lib/components/Find.tsx index e1e861b620..c8949ec34c 100644 --- a/libs/remix-ui/search/src/lib/components/Find.tsx +++ b/libs/remix-ui/search/src/lib/components/Find.tsx @@ -2,7 +2,13 @@ import React, { useContext } from 'react' import { SearchContext } from '../context/context' export const Find = props => { - const { setFind, state, toggleCaseSensitive, toggleMatchWholeWord } = useContext(SearchContext) + const { + setFind, + state, + toggleCaseSensitive, + toggleMatchWholeWord, + toggleUseRegex + } = useContext(SearchContext) let timeOutId: any = null const change = e => { clearTimeout(timeOutId) @@ -21,11 +27,13 @@ export const Find = props => { >
{ toggleCaseSensitive() @@ -33,7 +41,9 @@ export const Find = props => { >
{ toggleMatchWholeWord() }} >
+
{ + toggleUseRegex() + }} + >
diff --git a/libs/remix-ui/search/src/lib/components/Search.tsx b/libs/remix-ui/search/src/lib/components/Search.tsx index 5bddd417c8..05a856832e 100644 --- a/libs/remix-ui/search/src/lib/components/Search.tsx +++ b/libs/remix-ui/search/src/lib/components/Search.tsx @@ -13,7 +13,7 @@ const plugin = props.plugin return ( <> -
+
diff --git a/libs/remix-ui/search/src/lib/components/results/ResultFileName.tsx b/libs/remix-ui/search/src/lib/components/results/ResultFileName.tsx index 8df5162bbe..45257371e2 100644 --- a/libs/remix-ui/search/src/lib/components/results/ResultFileName.tsx +++ b/libs/remix-ui/search/src/lib/components/results/ResultFileName.tsx @@ -1,18 +1,25 @@ -import React from 'react' +import React, { useEffect, useState } from 'react' import { SearchResult } from '../../types' - +import { getPathIcon } from '@remix-ui/helper' interface ResultItemProps { file: SearchResult } export const ResultFileName = (props: ResultItemProps) => { + const [icon, setIcon] = useState('') + + useEffect(() => { + if (props.file && props.file.path) { + setIcon(getPathIcon(props.file.path)) + } + }, [props.file]) + return ( -
-
- - {props.file.filename} - + <> + {icon ?
: null} +
+ {props.file.filename}
-
+ ) } diff --git a/libs/remix-ui/search/src/lib/components/results/ResultSummary.tsx b/libs/remix-ui/search/src/lib/components/results/ResultSummary.tsx index 18b76950f6..7fca1a87ac 100644 --- a/libs/remix-ui/search/src/lib/components/results/ResultSummary.tsx +++ b/libs/remix-ui/search/src/lib/components/results/ResultSummary.tsx @@ -17,7 +17,11 @@ export const ResultSummary = (props: ResultSummaryProps) => { const replace = async (line: SearchResultLineLine) => { props.setLoading(true) - await replaceText(props.searchResult, line) + try{ + await replaceText(props.searchResult, line) + }catch(e){ + props.setLoading(false) + } } return ( diff --git a/libs/remix-ui/search/src/lib/components/results/SearchHelper.ts b/libs/remix-ui/search/src/lib/components/results/SearchHelper.ts index 88ae6b1de1..3daa49f4bf 100644 --- a/libs/remix-ui/search/src/lib/components/results/SearchHelper.ts +++ b/libs/remix-ui/search/src/lib/components/results/SearchHelper.ts @@ -104,5 +104,8 @@ export const replaceTextInLine = (str: string, searchResultLine: SearchResultLin }).join(getEOL(str)) } +export function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} diff --git a/libs/remix-ui/search/src/lib/context/context.tsx b/libs/remix-ui/search/src/lib/context/context.tsx index c3f387857c..6ba9ba86c1 100644 --- a/libs/remix-ui/search/src/lib/context/context.tsx +++ b/libs/remix-ui/search/src/lib/context/context.tsx @@ -1,28 +1,38 @@ import React, { useEffect } from 'react' import { createContext, useReducer } from 'react' -import { findLinesInStringWithMatch, getDirectory, replaceTextInLine } from '../components/results/SearchHelper' import { - SearchReducer, -} from '../reducers/Reducer' -import { SearchState, SearchResult, SearchResultLine, SearchResultLineLine, SearchingInitialState } from '../types' + findLinesInStringWithMatch, + getDirectory, + replaceTextInLine +} from '../components/results/SearchHelper' +import { SearchReducer } from '../reducers/Reducer' +import { + SearchState, + SearchResult, + SearchResultLine, + SearchResultLineLine, + SearchingInitialState +} from '../types' import { filePathFilter } from '@jsdevtools/file-path-filter' +import { escapeRegExp } from 'lodash' export interface SearchingStateInterface { state: SearchState setFind: (value: string) => void setReplace: (value: string) => void - setInclude: (value: string) => void, - setExclude: (value: string) => void, - setCaseSensitive: (value: boolean) => void, - setRegex: (value: boolean) => void, - setWholeWord: (value: boolean) => void, - setSearchResults: (value: SearchResult[]) => void, - findText: (path: string) => Promise, - hightLightInPath: (result:SearchResult, line:SearchResultLineLine) => void, - replaceText: (result: SearchResult, line: SearchResultLineLine) => void, - reloadFile: (file:string) => void, - toggleCaseSensitive: () => void, - toggleMatchWholeWord: () => void, + setInclude: (value: string) => void + setExclude: (value: string) => void + setCaseSensitive: (value: boolean) => void + setRegex: (value: boolean) => void + setWholeWord: (value: boolean) => void + setSearchResults: (value: SearchResult[]) => void + findText: (path: string) => Promise + hightLightInPath: (result: SearchResult, line: SearchResultLineLine) => void + replaceText: (result: SearchResult, line: SearchResultLineLine) => void + reloadFile: (file: string) => void + toggleCaseSensitive: () => void + toggleMatchWholeWord: () => void + toggleUseRegex: () => void } export const SearchContext = createContext(null) @@ -86,12 +96,18 @@ export const SearchProvider = ({ payload: value }) }, - reloadFile: async (file:string) => { + reloadFile: async (file: string) => { dispatch({ type: 'RELOAD_FILE', payload: file }) }, + toggleUseRegex: () => { + dispatch({ + type: 'TOGGLE_USE_REGEX', + payload: undefined + }) + }, toggleCaseSensitive: () => { dispatch({ type: 'TOGGLE_CASE_SENSITIVE', @@ -104,29 +120,47 @@ export const SearchProvider = ({ payload: undefined }) }, - findText : async (path: string) => { - if(!plugin) return + findText: async (path: string) => { + if (!plugin) return try { - if(state.find.length < 3) return + if (state.find.length < 3) return const text = await plugin.call('fileManager', 'readFile', path) let flags = 'g' let find = state.find - if(!state.casesensitive) flags += 'i' - if(state.matchWord) find = `\\b${find}\\b` + if (!state.casesensitive) flags += 'i' + if (state.matchWord) find = `\\b${find}\\b` + if (!state.useRegExp) find = escapeRegExp(find) const re = new RegExp(find, flags) const result: SearchResultLine[] = findLinesInStringWithMatch(text, re) return result } catch (e) {} }, - hightLightInPath: async(result: SearchResult, line: SearchResultLineLine) => { + hightLightInPath: async ( + result: SearchResult, + line: SearchResultLineLine + ) => { await plugin.call('editor', 'discardHighlight') await plugin.call('editor', 'highlight', line.position, result.path) }, - replaceText: async(result: SearchResult, line: SearchResultLineLine) => { - await plugin.call('editor', 'discardHighlight') - await plugin.call('editor', 'highlight', line.position, result.path) - const content = await plugin.call('fileManager', 'readFile', result.path) - await plugin.call('fileManager','setFile', result.path, replaceTextInLine(content, line, state.replace)) + replaceText: async (result: SearchResult, line: SearchResultLineLine) => { + try { + await plugin.call('editor', 'discardHighlight') + await plugin.call('editor', 'highlight', line.position, result.path) + const content = await plugin.call( + 'fileManager', + 'readFile', + result.path + ) + + await plugin.call( + 'fileManager', + 'setFile', + result.path, + replaceTextInLine(content, line, state.replace) + ) + } catch (e) { + throw new Error(e) + } } } @@ -173,8 +207,6 @@ export const SearchProvider = ({ } }, [state.timeStamp]) - - return ( <> {children} diff --git a/libs/remix-ui/search/src/lib/reducers/Reducer.ts b/libs/remix-ui/search/src/lib/reducers/Reducer.ts index 907a57b8c8..2738caa95f 100644 --- a/libs/remix-ui/search/src/lib/reducers/Reducer.ts +++ b/libs/remix-ui/search/src/lib/reducers/Reducer.ts @@ -40,6 +40,12 @@ export const SearchReducer = (state: SearchState = SearchingInitialState, action casesensitive: !state.casesensitive, timeStamp: Date.now() } + case 'TOGGLE_USE_REGEX': + return { + ...state, + useRegExp: !state.useRegExp, + timeStamp: Date.now() + } case 'TOGGLE_MATCH_WHOLE_WORD': return { ...state, diff --git a/libs/remix-ui/search/src/lib/search.css b/libs/remix-ui/search/src/lib/search.css index 089cae82ed..4f4dfbd5bb 100644 --- a/libs/remix-ui/search/src/lib/search.css +++ b/libs/remix-ui/search/src/lib/search.css @@ -5,6 +5,7 @@ -ms-user-select: none; /* IE10+/Edge */ user-select: none; /* Standard */ cursor: pointer; + align-items: center; } .wrap_summary { @@ -85,4 +86,10 @@ .search_tab .checked { background-color: var(--secondary); +} + +.search_tab .search_file_name { + text-overflow: ellipsis; + overflow: hidden; + text-transform: uppercase; } \ No newline at end of file diff --git a/libs/remix-ui/search/src/lib/types/index.ts b/libs/remix-ui/search/src/lib/types/index.ts index 7b558085f5..4521bfb658 100644 --- a/libs/remix-ui/search/src/lib/types/index.ts +++ b/libs/remix-ui/search/src/lib/types/index.ts @@ -40,6 +40,7 @@ export interface SearchState { exclude: string, casesensitive: boolean, matchWord: boolean, + useRegExp: boolean, timeStamp: number } @@ -51,5 +52,6 @@ export const SearchingInitialState: SearchState = { searchResults: [], casesensitive: false, matchWord: false, + useRegExp: false, timeStamp: 0 } \ No newline at end of file