pull/2170/head
filip mertens 3 years ago
parent d5ba20621f
commit 79ac970b69
  1. 2
      apps/remix-ide-e2e/src/tests/search.test.ts
  2. 16
      apps/remix-ide/src/app/editor/editor.js
  3. 2
      apps/remix-ide/src/app/tabs/search.tsx
  4. 37
      libs/remix-ui/editor/src/lib/actions/editor.ts
  5. 4
      libs/remix-ui/search/src/lib/components/Exclude.tsx
  6. 1
      libs/remix-ui/search/src/lib/components/Find.tsx
  7. 33
      libs/remix-ui/search/src/lib/components/FindContainer.tsx
  8. 4
      libs/remix-ui/search/src/lib/components/Include.tsx
  9. 8
      libs/remix-ui/search/src/lib/components/OverWriteCheck.tsx
  10. 2
      libs/remix-ui/search/src/lib/components/Replace.tsx
  11. 4
      libs/remix-ui/search/src/lib/components/Search.tsx
  12. 3
      libs/remix-ui/search/src/lib/components/results/ResultItem.tsx
  13. 7
      libs/remix-ui/search/src/lib/components/results/ResultSummary.tsx
  14. 8
      libs/remix-ui/search/src/lib/components/results/Results.tsx
  15. 10
      libs/remix-ui/search/src/lib/context/context.tsx
  16. 6
      libs/remix-ui/search/src/lib/reducers/Reducer.ts
  17. 17
      libs/remix-ui/search/src/lib/search.css
  18. 8
      libs/remix-ui/search/src/lib/types/index.ts

@ -67,6 +67,8 @@ module.exports = {
},
'Should replace text': function (browser: NightwatchBrowser) {
browser
.waitForElementVisible('*[data-id="toggle_replace"]').click('*[data-id="toggle_replace"]')
.waitForElementVisible('*[id="search_replace"]')
.setValue('*[id="search_replace"]', 'replacing').pause(1000)
.waitForElementVisible('*[data-id="contracts/2_Owner.sol-30-71"]')
.moveToElement('*[data-id="contracts/2_Owner.sol-30-71"]', 10, 10)

@ -12,7 +12,7 @@ const profile = {
name: 'editor',
description: 'service - editor',
version: packageJson.version,
methods: ['highlight', 'discardHighlight', 'clearAnnotations', 'addAnnotation', 'gotoLine', 'getCursorPosition']
methods: ['highlight', 'discardHighlight', 'clearAnnotations', 'addAnnotation', 'gotoLine', 'revealRange', 'getCursorPosition']
}
class Editor extends Plugin {
@ -390,6 +390,20 @@ class Editor extends Plugin {
this.emit('revealLine', line + 1, col)
}
/**
* Reveals the range in the editor.
* @param {number} startLineNumber
* @param {number} startColumn
* @param {number} endLineNumber
* @param {number} endColumn
*/
revealRange (startLineNumber, startColumn, endLineNumber, endColumn) {
if (!this.activated) return
this.emit('focus')
console.log(startLineNumber, startColumn, endLineNumber, endColumn)
this.emit('revealRange', startLineNumber, startColumn, endLineNumber, endColumn)
}
/**
* Scrolls to a line. If center is true, it puts the line in middle of screen (or attempts to).
* @param {number} line The line to scroll to

@ -4,7 +4,7 @@ import React from 'react' // eslint-disable-line
import { SearchTab } from '@remix-ui/search'
const profile = {
name: 'search',
displayName: 'Search',
displayName: 'Search in files',
methods: [''],
events: [],
icon: 'assets/img/Search_Icon.svg',

@ -1,3 +1,5 @@
import { IRange } from "monaco-editor";
export interface Action {
type: string;
payload: Record<string, any>
@ -49,6 +51,27 @@ export const reducerActions = (models = initialState, action: Action) => {
editor.setPosition({ column, lineNumber: line })
return models
}
case 'REVEAL_RANGE': {
if (!editor) return models
const range: IRange = {
startLineNumber: action.payload.startLineNumber +1,
startColumn: action.payload.startColumn,
endLineNumber: action.payload.endLineNumber + 1,
endColumn: action.payload.endColumn
}
// reset to start of line
if(action.payload.startColumn < 100){
editor.revealRange({
startLineNumber: range.startLineNumber,
startColumn: 1,
endLineNumber: range.endLineNumber,
endColumn: 1
})
}else{
editor.revealRangeInCenter(range)
}
return models
}
case 'FOCUS': {
if (!editor) return models
editor.focus()
@ -106,6 +129,20 @@ export const reducerListener = (plugin, dispatch, monaco, editor, events) => {
})
})
plugin.on('editor', 'revealRange', (startLineNumber, startColumn, endLineNumber, endColumn) => {
dispatch({
type: 'REVEAL_RANGE',
payload: {
startLineNumber,
startColumn,
endLineNumber,
endColumn
},
monaco,
editor
})
})
plugin.on('editor', 'focus', () => {
dispatch({
type: 'FOCUS',

@ -17,8 +17,8 @@ export const Exclude = props => {
return (
<>
<div className="search_plugin_find-part">
<label>exclude</label>
<div className="search_plugin_find-part pl-3">
<label>files to exclude</label>
<input
id='search_exclude'
placeholder="Exclude ie .git/**/*"

@ -18,7 +18,6 @@ export const Find = () => {
return (
<>
<div className="search_plugin_find-part">
<label>search</label>
<div className="search_plugin_search-input">
<input
id='search_input'

@ -0,0 +1,33 @@
import React, { useContext, useEffect, useState } from 'react'
import { SearchContext } from '../context/context'
import { Find } from './Find'
import { Replace } from './Replace'
export const FindContainer = props => {
const { setReplaceEnabled } = useContext(SearchContext)
const [expanded, setExpanded] = useState<boolean>(false)
const toggleExpand = () => setExpanded(!expanded)
useEffect(() => {
setReplaceEnabled(expanded)
}, [expanded])
return (
<div className="search_plugin_find_container">
<div
title="Toggle Replace"
data-id="toggle_replace"
className={`codicon codicon-find-${
expanded ? 'expanded' : 'collapsed'
} search_plugin_find_container_arrow`}
role="button"
onClick={toggleExpand}
aria-label="Toggle Replace"
aria-expanded="true"
aria-disabled="false"
></div>
<div className="search_plugin_find_container_internal">
<Find></Find>
{expanded ? <Replace></Replace> : null}
</div>
</div>
)
}

@ -13,8 +13,8 @@ export const Include = props => {
return (
<>
<div className="search_plugin_find-part">
<label>include</label>
<div className="search_plugin_find-part pl-3">
<label>files to include</label>
<input
id='search_include'
placeholder="Include ie contracts/**/*.sol"

@ -2,7 +2,7 @@ import React, { useContext } from 'react'
import { SearchContext } from '../context/context'
export const OverWriteCheck = props => {
const { setReplaceWithoutConfirmation } = useContext(SearchContext)
const { setReplaceWithoutConfirmation, state } = useContext(SearchContext)
const change = e => {
setReplaceWithoutConfirmation(e.target.checked)
@ -10,7 +10,8 @@ export const OverWriteCheck = props => {
return (
<>
<div className="search_plugin_find-part">
{state.replaceEnabled ? (
<div className="search_plugin_find-part pl-3">
<div className="mb-2 remixui_nightlyBuilds custom-control custom-checkbox">
<input
className="mr-2 custom-control-input"
@ -19,7 +20,7 @@ export const OverWriteCheck = props => {
onChange={change}
/>
<label
htmlFor='confirm_replace'
htmlFor="confirm_replace"
data-id="confirm_replace_label"
className="form-check-label custom-control-label"
>
@ -27,6 +28,7 @@ export const OverWriteCheck = props => {
</label>
</div>
</div>
) : null}
</>
)
}

@ -12,7 +12,7 @@ export const Replace = props => {
return (
<>
<div className="search_plugin_find-part">
<label>replace</label>
<label>replace in files</label>
<input
id='search_replace'
placeholder="Replace"

@ -7,6 +7,7 @@ import { Include } from './Include'
import { Exclude } from './Exclude'
import { Replace } from './Replace'
import { OverWriteCheck } from './OverWriteCheck'
import { FindContainer } from './FindContainer'
export const SearchTab = props => {
@ -16,8 +17,7 @@ return (
<>
<div className="search_plugin_search_tab pl-2 pr-2">
<SearchProvider plugin={plugin}>
<Find></Find>
<Replace></Replace>
<FindContainer></FindContainer>
<Include></Include>
<Exclude></Exclude>
<OverWriteCheck></OverWriteCheck>

@ -86,12 +86,13 @@ export const ResultItem = (props: ResultItemProps) => {
{!toggleExpander && !loading ? (
<div className="p-1 search_plugin_wrap_summary">
{lines.map((line, index) => (
index < state.maxLines ?
<ResultSummary
setLoading={setLoading}
key={index}
searchResult={props.file}
line={line}
/>
/>: null
))}
</div>
) : null}

@ -47,15 +47,16 @@ export const ResultSummary = (props: ResultSummaryProps) => {
className='search_plugin_search_line pb-1'
>
<div className='search_plugin_summary_left'>{lineItem.left.substring(lineItem.left.length - 20).trimStart()}</div>
<mark className={`search_plugin_summary_center ${state.replace? 'search_plugin_replace_strike':''}`}>{lineItem.center}</mark>
{state.replace? <mark className='search_plugin_replacement'>{state.replace}</mark>:<></>}
<mark className={`search_plugin_summary_center ${state.replace && state.replaceEnabled? 'search_plugin_replace_strike':''}`}>{lineItem.center}</mark>
{state.replace && state.replaceEnabled? <mark className='search_plugin_replacement'>{state.replace}</mark>:<></>}
<div className='search_plugin_summary_right'>{lineItem.right.substring(0, 100)}</div>
</div>
{state.replaceEnabled?
<div className='search_plugin_search_control'>
<div title="Replace" data-id={`replace-${props.searchResult.filename}-${lineItem.position.start.line}-${lineItem.position.start.column}`} onClick={async () => {
replace(lineItem)
}} className="codicon codicon-find-replace" role="button" aria-label="Replace" aria-disabled="false"></div>
</div>
</div>:null}
</div>
))}
</>

@ -5,13 +5,13 @@ import { ResultItem } from './ResultItem'
export const Results = () => {
const { state } = useContext(SearchContext)
return (
<div data-id='search_results'>
<div data-id='search_results' className='mt-2'>
{state.find ? <div className='search_plugin_result_count_number badge badge-pill badge-secondary'>{state.count} results</div>: null}
{state.count < state.maxResults && state.searchResults &&
{state.find && state.count >= state.maxResults? <div className='alert alert-warning mt-1'>The result set only contains a subset of all matches<br></br>Please narrow down your search.</div>: null}
{state.searchResults &&
state.searchResults.map((result, index) => {
return <ResultItem key={index} file={result} />
return index <state.maxFiles? <ResultItem key={index} file={result} />: null
})}
{state.find && state.count >= state.maxResults? <div className='alert alert-warning mt-1'>Too many results to display.<br></br>Please narrow your search.</div>: null}
</div>
)
}

@ -20,6 +20,7 @@ export interface SearchingStateInterface {
state: SearchState
setFind: (value: string) => void
setReplace: (value: string) => void
setReplaceEnabled: (value: boolean) => void
setInclude: (value: string) => void
setExclude: (value: string) => void
setCaseSensitive: (value: boolean) => void
@ -63,6 +64,12 @@ export const SearchProvider = ({
payload: value
})
},
setReplaceEnabled: (value: boolean) => {
dispatch({
type: 'SET_REPLACE_ENABLED',
payload: value
})
},
setInclude: (value: string) => {
dispatch({
type: 'SET_INCLUDE',
@ -144,7 +151,7 @@ export const SearchProvider = ({
findText: async (path: string) => {
if (!plugin) return
try {
if (state.find.length < 3) return
if (state.find.length < 1) return
const text = await plugin.call('fileManager', 'readFile', path)
let flags = 'g'
let find = state.find
@ -162,6 +169,7 @@ export const SearchProvider = ({
) => {
await plugin.call('editor', 'discardHighlight')
await plugin.call('editor', 'highlight', line.position, result.path)
await plugin.call('editor', 'revealRange', line.position.start.line, line.position.start.column, line.position.end.line, line.position.end.column)
},
replaceText: async (result: SearchResult, line: SearchResultLineLine) => {
try {

@ -15,6 +15,12 @@ export const SearchReducer = (state: SearchState = SearchingInitialState, action
replace: action.payload,
}
case 'SET_REPLACE_ENABLED':
return {
...state,
replaceEnabled: action.payload,
}
case 'SET_INCLUDE':
return {
...state,

@ -104,3 +104,20 @@
.search_plugin_search_tab .search_plugin_result_count_number {
font-size: x-small;
}
.search_plugin_find_container {
display: flex;
flex-direction: row;
}
.search_plugin_find_container_internal {
display: flex;
flex-direction: column;
flex-grow: 1;
}
.search_plugin_find_container_arrow {
display: flex !important;
align-items: center;
cursor: pointer !important;
}

@ -39,6 +39,7 @@ export interface SearchState {
find: string,
searchResults: SearchResult[],
replace: string,
replaceEnabled: boolean,
include: string,
exclude: string,
casesensitive: boolean,
@ -48,6 +49,8 @@ export interface SearchState {
timeStamp: number,
count: number,
maxResults: number
maxFiles: number,
maxLines: number
}
export const SearchingInitialState: SearchState = {
@ -55,6 +58,7 @@ export const SearchingInitialState: SearchState = {
replace: '',
include: '',
exclude: '',
replaceEnabled: false,
searchResults: [],
casesensitive: false,
matchWord: false,
@ -62,5 +66,7 @@ export const SearchingInitialState: SearchState = {
replaceWithOutConfirmation: false,
timeStamp: 0,
count: 0,
maxResults: 500
maxResults: 1500,
maxFiles: 100,
maxLines: 200
}
Loading…
Cancel
Save