diff --git a/libs/remix-ui/search/src/lib/components/Exclude.tsx b/libs/remix-ui/search/src/lib/components/Exclude.tsx
index e69de29bb2..e755f1370e 100644
--- a/libs/remix-ui/search/src/lib/components/Exclude.tsx
+++ b/libs/remix-ui/search/src/lib/components/Exclude.tsx
@@ -0,0 +1,26 @@
+import React, { useContext, useEffect } from 'react'
+import { SearchContext } from '../context/context'
+
+export const Exclude = props => {
+ const { setExclude } = useContext(SearchContext)
+ const change = e => {
+ const timeOutId = setTimeout(() => setExclude(e.target.value), 500)
+ return () => clearTimeout(timeOutId)
+ }
+
+ useEffect(() => {
+ setExclude('.git/**')
+ }, [])
+
+ return (
+ <>
+
+
+
+ >
+ )
+}
diff --git a/libs/remix-ui/search/src/lib/components/Find.tsx b/libs/remix-ui/search/src/lib/components/Find.tsx
index db8cb94463..ef15cb1c81 100644
--- a/libs/remix-ui/search/src/lib/components/Find.tsx
+++ b/libs/remix-ui/search/src/lib/components/Find.tsx
@@ -1,17 +1,40 @@
-import React, { useContext, useReducer } from "react"
-import { SearchContext } from "../context/context"
-import { SearchingInitialState, SearchReducer } from "../reducers/Reducer"
-
-
+import React, { useContext } from 'react'
+import { SearchContext } from '../context/context'
export const Find = props => {
+ const { setFind } = useContext(SearchContext)
+ const change = e => {
+ const timeOutId = setTimeout(() => setFind(e.target.value), 500)
+ return () => clearTimeout(timeOutId)
+ }
- const { setFind } = useContext(SearchContext)
- const change = (e) => {
- setFind(e.target.value)
- }
-
- return(<>
-
- >)
-}
\ No newline at end of file
+ return (
+ <>
+
+ >
+ )
+}
diff --git a/libs/remix-ui/search/src/lib/components/Include.tsx b/libs/remix-ui/search/src/lib/components/Include.tsx
index e69de29bb2..bea364a6c9 100644
--- a/libs/remix-ui/search/src/lib/components/Include.tsx
+++ b/libs/remix-ui/search/src/lib/components/Include.tsx
@@ -0,0 +1,22 @@
+import React, { useContext } from 'react'
+import { SearchContext } from '../context/context'
+
+export const Include = props => {
+ const { setInclude } = useContext(SearchContext)
+ const change = e => {
+ const timeOutId = setTimeout(() => setInclude(e.target.value), 500)
+ return () => clearTimeout(timeOutId)
+ }
+
+ return (
+ <>
+
+
+
+ >
+ )
+}
diff --git a/libs/remix-ui/search/src/lib/components/Replace.tsx b/libs/remix-ui/search/src/lib/components/Replace.tsx
index fc60d3d73a..28712774ca 100644
--- a/libs/remix-ui/search/src/lib/components/Replace.tsx
+++ b/libs/remix-ui/search/src/lib/components/Replace.tsx
@@ -1,16 +1,22 @@
-import React, { useContext, useEffect } from 'react'
+import React, { useContext } from 'react'
import { SearchContext } from '../context/context'
export const Replace = props => {
- const { state, setReplace } = useContext(SearchContext)
-
+ const { setReplace } = useContext(SearchContext)
const change = e => {
- setReplace(e.target.value)
+ const timeOutId = setTimeout(() => setReplace(e.target.value), 500)
+ return () => clearTimeout(timeOutId)
}
return (
<>
-
+
+
+
>
)
}
diff --git a/libs/remix-ui/search/src/lib/components/Search.tsx b/libs/remix-ui/search/src/lib/components/Search.tsx
index e9d2df1097..913e00eab2 100644
--- a/libs/remix-ui/search/src/lib/components/Search.tsx
+++ b/libs/remix-ui/search/src/lib/components/Search.tsx
@@ -1,23 +1,21 @@
-import React, { useContext, useEffect, useReducer } from 'react'
-import { SearchContext, SearchProvider } from '../context/context'
-import { SearchingInitialState, SearchReducer } from '../reducers/Reducer'
+import React from 'react'
+import { SearchProvider } from '../context/context'
import { Find } from './Find'
-import { Replace } from './Replace'
import { Results } from './results/Results'
+import '../search.css'
+import { Include } from './Include'
+import { Exclude } from './Exclude'
export const SearchTab = props => {
const plugin = props.plugin
-useEffect(() => {
- console.log (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 e69de29bb2..2d297a078a 100644
--- a/libs/remix-ui/search/src/lib/components/results/ResultFileName.tsx
+++ b/libs/remix-ui/search/src/lib/components/results/ResultFileName.tsx
@@ -0,0 +1,20 @@
+import { ViewPlugin } from '@remixproject/engine-web'
+import React, { useContext, useEffect } from 'react'
+import { SearchContext } from '../../context/context'
+import { SearchResult } from '../../reducers/Reducer'
+
+interface ResultItemProps {
+ file: SearchResult
+}
+
+export const ResultFileName = (props: ResultItemProps) => {
+ return (
+
+
+
+ {props.file.filename}
+
+
+
+ )
+}
diff --git a/libs/remix-ui/search/src/lib/components/results/ResultItem.tsx b/libs/remix-ui/search/src/lib/components/results/ResultItem.tsx
index e69de29bb2..54785a714d 100644
--- a/libs/remix-ui/search/src/lib/components/results/ResultItem.tsx
+++ b/libs/remix-ui/search/src/lib/components/results/ResultItem.tsx
@@ -0,0 +1,64 @@
+import { ViewPlugin } from '@remixproject/engine-web'
+import React, { useContext, useEffect, useState } from 'react'
+import { SearchContext } from '../../context/context'
+import { SearchResult, SearchResultLine } from '../../reducers/Reducer'
+import { ResultFileName } from './ResultFileName'
+import { ResultSummary } from './ResultSummary'
+
+interface ResultItemProps {
+ file: SearchResult
+}
+
+export const ResultItem = (props: ResultItemProps) => {
+ const { state, findText } = useContext(SearchContext)
+
+ const [lines, setLines] = useState([])
+ const [toggleExpander, setToggleExpander] = useState(false)
+
+ useEffect(() => {
+ if (!props.file.searchComplete) {
+ // console.log('searching for: ' + props.file.filename)
+ }
+ }, [props.file.searchComplete])
+
+ const toggleClass = () => {
+ setToggleExpander(!toggleExpander)
+ }
+
+ useEffect(() => {
+ if (!props.file.searchComplete) {
+ findText(props.file.filename).then(res => {
+ setLines(res)
+ })
+ }
+ }, [state.find])
+
+ return (
+ <>
+ {lines && lines.length ? (
+ <>
+
+ {' '}
+
+
+ {!toggleExpander ? (
+
+ {lines.map((line, index) => (
+
+ ))}
+
+ ) : null}
+ >
+ ) : (
+ <>>
+ )}
+ >
+ )
+}
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 e69de29bb2..f86d842212 100644
--- a/libs/remix-ui/search/src/lib/components/results/ResultSummary.tsx
+++ b/libs/remix-ui/search/src/lib/components/results/ResultSummary.tsx
@@ -0,0 +1,34 @@
+import { ViewPlugin } from '@remixproject/engine-web'
+import React, { useContext, useEffect, useState } from 'react'
+import { SearchContext } from '../../context/context'
+import { SearchResult, SearchResultLine, SearchResultLineLine } from '../../reducers/Reducer'
+import { ResultFileName } from './ResultFileName'
+
+interface ResultSummaryProps {
+ searchResult: SearchResult
+ line: SearchResultLine
+}
+
+export const ResultSummary = (props: ResultSummaryProps) => {
+ const { hightLightInPath } = useContext(SearchContext)
+ const selectLine = async (line: SearchResultLineLine) => {
+ console.log(line, props.searchResult)
+ await hightLightInPath(props.searchResult, line)
+ }
+ return (
+
+ {props.line.lines.map((lineItem, index) => (
+ {
+ selectLine(lineItem)
+ }}
+ key={index}
+ >
+ {lineItem.left.substring(lineItem.left.length - 20)}
+ {lineItem.center}
+ {lineItem.right.substring(0, 100)}
+
+ ))}
+
+ )
+}
diff --git a/libs/remix-ui/search/src/lib/components/results/Results.tsx b/libs/remix-ui/search/src/lib/components/results/Results.tsx
index 7514c51e98..ca109573fb 100644
--- a/libs/remix-ui/search/src/lib/components/results/Results.tsx
+++ b/libs/remix-ui/search/src/lib/components/results/Results.tsx
@@ -1,81 +1,98 @@
-import { ViewPlugin } from "@remixproject/engine-web"
-import React, { useContext, useEffect } from "react"
-import { SearchContext } from "../../context/context"
-import { SearchResult } from "../../reducers/Reducer"
+import { ViewPlugin } from '@remixproject/engine-web'
+import { matches } from 'lodash'
+import React, { useContext, useEffect, useState } from 'react'
+import { SearchContext } from '../../context/context'
+import { SearchResult, SearchResultLine } from '../../reducers/Reducer'
+import { ResultItem } from './ResultItem'
+import { findLinesInStringWithMatch } from './SearchHelper'
+const filePathFilter = require('@jsdevtools/file-path-filter')
interface ResultsProps {
- plugin: ViewPlugin
+ plugin: ViewPlugin
}
export const Results = (props: ResultsProps) => {
+ const { state, setSearchResults, setFind } = useContext(SearchContext)
+ const [ alertText, setAlertText ] = useState('')
+ const { plugin } = props
- const { state, setSearchResults } = useContext(SearchContext)
-
- const { plugin } = props
-
- const getDirectory = async (dir) => {
- let result = []
- const files = await plugin.call('fileManager', 'readdir', dir)
- const fileArray = normalize(files)
- for (const fi of fileArray) {
- if (fi) {
- const type = fi.data.isDirectory
- if (type === true) {
- result = [
- ...result,
- ...(await getDirectory(
- `${fi.filename}`
- ))
- ]
- } else {
- result = [...result, fi.filename]
- }
- }
+ const getDirectory = async (dir: string) => {
+ let result = []
+ const files = await plugin.call('fileManager', 'readdir', dir)
+ const fileArray = normalize(files)
+ for (const fi of fileArray) {
+ if (fi) {
+ const type = fi.data.isDirectory
+ if (type === true) {
+ result = [...result, ...(await getDirectory(`${fi.filename}`))]
+ } else {
+ result = [...result, fi.filename]
}
- return result
+ }
}
+ return result
+ }
- const normalize = (filesList) => {
- const folders = []
- const files = []
- Object.keys(filesList || {}).forEach(key => {
- if (filesList[key].isDirectory) {
- folders.push({
- filename: key,
- data: filesList[key]
- })
- } else {
- files.push({
- filename: key,
- data: filesList[key]
- })
- }
+ const normalize = filesList => {
+ const folders = []
+ const files = []
+ Object.keys(filesList || {}).forEach(key => {
+ if (filesList[key].isDirectory) {
+ folders.push({
+ filename: key,
+ data: filesList[key]
+ })
+ } else {
+ files.push({
+ filename: key,
+ data: filesList[key]
})
- return [...folders, ...files]
}
+ })
+ return [...folders, ...files]
+ }
- useEffect(() => {
- if (state.find) {
- getDirectory('/').then(res => {
- const ob = res.map(file => {
- const r:SearchResult = {
- filename: file,
- lines: [],
- path: file,
- searchComplete: false
- }
- return r
- })
- console.log(ob)
- setSearchResults(ob)
- })
- }
- },[state.find])
+ useEffect(() => {
+ plugin.on('filePanel', 'setWorkspace', () => {
+ setSearchResults(null)
+ })
+ return () => plugin.off('filePanel', 'setWorkspace')
+ }, [])
+ useEffect(() => {
+ if (state.find) {
+ (async () => {
+ const res = await getDirectory('/')
+ const pathFilter: any = {}
+ if (state.include)
+ pathFilter.include = state.include.split(',').map(i => i.trim())
+ if (state.exclude)
+ pathFilter.exclude = state.exclude.split(',').map(i => i.trim())
+ const ob = res.filter(filePathFilter(pathFilter)).map(file => {
+ const r: SearchResult = {
+ filename: file,
+ lines: [],
+ path: file,
+ searchComplete: false
+ }
+ return r
+ })
+ setSearchResults(ob)
+ })()
+ }
+ }, [state.find, state.replace, state.include, state.exclude])
- useEffect(() => {
- console.log(state.searchResults)
- },[state.searchResults])
-
- return(<>>)
-}
\ No newline at end of file
+ return (
+ <>
+ {alertText ? (
+
+ {alertText}
+
+ ) : null}
+ {state.searchResults &&
+ state.searchResults.map((result, index) => {
+ 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
new file mode 100644
index 0000000000..3e41e418ca
--- /dev/null
+++ b/libs/remix-ui/search/src/lib/components/results/SearchHelper.ts
@@ -0,0 +1,45 @@
+import { SearchResultLineLine } from "../../reducers/Reducer"
+
+export const findLinesInStringWithMatch = (str: string, re: RegExp) => {
+ return str
+ .split(/\r?\n/)
+ .map(function (line, i) {
+ const matchResult = matchesInString(line, re)
+ if (matchResult.length) {
+ return {
+ lines: splitLines(matchResult, i),
+ }
+ }
+ })
+ .filter(Boolean)
+}
+
+const matchesInString = (str: string, re: RegExp) => {
+ let a: RegExpExecArray
+ let results:RegExpExecArray[] = [];
+ while ((a = re.exec(str || '')) !== null) {
+ results.push(a);
+ }
+ return results
+}
+
+const splitLines = (matchResult: RegExpExecArray[], lineNumber: number) => {
+ return matchResult.map((matchResultPart, i) => {
+ const result:SearchResultLineLine = {
+ left: matchResultPart.input.substring(0, matchResultPart.index),
+ right: matchResultPart.input.substring(matchResultPart.index + matchResultPart[0].length),
+ center: matchResultPart[0],
+ position : {
+ start: {
+ line: lineNumber,
+ column: matchResultPart.index,
+ },
+ end: {
+ line: lineNumber,
+ column: matchResultPart.index + matchResultPart[0].length,
+ },
+ },
+ }
+ return result
+ })
+}
diff --git a/libs/remix-ui/search/src/lib/context/context.tsx b/libs/remix-ui/search/src/lib/context/context.tsx
index 4b696f948e..1762d7c367 100644
--- a/libs/remix-ui/search/src/lib/context/context.tsx
+++ b/libs/remix-ui/search/src/lib/context/context.tsx
@@ -1,9 +1,12 @@
import React from 'react'
import { createContext, useReducer } from 'react'
+import { findLinesInStringWithMatch } from '../components/results/SearchHelper'
import {
SearchingInitialState,
SearchReducer,
SearchResult,
+ SearchResultLine,
+ SearchResultLineLine,
SearchState
} from '../reducers/Reducer'
@@ -17,6 +20,8 @@ export interface SearchingStateInterface {
setRegex: (value: boolean) => void,
setWholeWord: (value: boolean) => void,
setSearchResults: (value: SearchResult[]) => void,
+ findText: (path: string) => Promise,
+ hightLightInPath: (path:SearchResult, line:SearchResultLineLine) => void,
}
export const SearchContext = createContext(null)
@@ -24,13 +29,15 @@ export const SearchContext = createContext(null)
export const SearchProvider = ({
children = [],
reducer = SearchReducer,
- initialState = SearchingInitialState
+ initialState = SearchingInitialState,
+ plugin = undefined
} = {}) => {
const [state, dispatch] = useReducer(reducer, initialState)
const value = {
state,
setFind: (value: string) => {
+ console.log('setFind: ' + value)
dispatch({
type: 'SET_FIND',
payload: value
@@ -77,7 +84,23 @@ export const SearchProvider = ({
type: 'SET_SEARCH_RESULTS',
payload: value
})
- }
+ },
+ findText : async (path: string) => {
+ if(!plugin) return
+ try {
+ if(state.find.length < 3) return
+ const text = await plugin.call('fileManager', 'readFile', path)
+ const re = new RegExp(state.find, 'gi')
+ const result: SearchResultLine[] = findLinesInStringWithMatch(text, re)
+ // console.log(result, path)
+ return result
+ } catch (e) {}
+ },
+ hightLightInPath: async(result: SearchResult, line: SearchResultLineLine) => {
+ await plugin.call('editor', 'discardHighlight')
+ await plugin.call('editor', 'highlight', line.position, result.path)
+ }
+
}
return (
diff --git a/libs/remix-ui/search/src/lib/reducers/Reducer.ts b/libs/remix-ui/search/src/lib/reducers/Reducer.ts
index e0cc2a4b0c..c4a6742a08 100644
--- a/libs/remix-ui/search/src/lib/reducers/Reducer.ts
+++ b/libs/remix-ui/search/src/lib/reducers/Reducer.ts
@@ -4,9 +4,25 @@ interface Action {
payload: any
}
+interface position {
+ start: {
+ line: number
+ column: number
+ },
+ end: {
+ line: number
+ column: number
+ }
+ }
+
+export interface SearchResultLineLine {
+ left: any,
+ center: any,
+ right: any,
+ position: position
+}
export interface SearchResultLine {
- lineNumber: number
- text: string
+ lines: SearchResultLineLine[]
}
export interface SearchResult {
@@ -33,38 +49,37 @@ export const SearchingInitialState: SearchState = {
}
export const SearchReducer = (state: SearchState = SearchingInitialState, action: Action) => {
- console.log(state)
switch (action.type) {
case 'SET_FIND':
return {
...state,
find: action.payload,
}
- break;
+
case 'SET_REPLACE':
return {
...state,
replace: action.payload,
}
- break;
+
case 'SET_INCLUDE':
return {
...state,
include: action.payload,
}
- break;
+
case 'SET_EXCLUDE':
return {
...state,
exclude: action.payload,
}
- break;
+
case 'SET_SEARCH_RESULTS':
return {
...state,
searchResults: action.payload,
}
- break;
+
default:
}
}
\ No newline at end of file
diff --git a/libs/remix-ui/search/src/lib/search.css b/libs/remix-ui/search/src/lib/search.css
new file mode 100644
index 0000000000..a7b9326785
--- /dev/null
+++ b/libs/remix-ui/search/src/lib/search.css
@@ -0,0 +1,26 @@
+.search_result_item_title {
+ display: flex;
+ -webkit-user-select: none; /* Safari */
+ -moz-user-select: none; /* Firefox */
+ -ms-user-select: none; /* IE10+/Edge */
+ user-select: none; /* Standard */
+ cursor: pointer;
+}
+
+.wrap_summary {
+ overflow: hidden;
+ white-space: nowrap;
+ -webkit-user-select: none; /* Safari */
+ -moz-user-select: none; /* Firefox */
+ -ms-user-select: none; /* IE10+/Edge */
+ user-select: none; /* Standard */
+ cursor: pointer;
+}
+
+.find-part {
+ display: flex;
+}
+
+.controls {
+ display: flex;
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index 3585888453..a38866094a 100644
--- a/package.json
+++ b/package.json
@@ -171,6 +171,7 @@
"ethers": "^5.4.2",
"ethjs-util": "^0.1.6",
"express-ws": "^4.0.0",
+ "file-path-filter": "^3.0.2",
"file-saver": "^2.0.5",
"form-data": "^4.0.0",
"fs-extra": "^3.0.1",