From 67de39692720a6d16dbcad18760e25673d24202c Mon Sep 17 00:00:00 2001 From: Bruno Braga <45981620+brunobragaw8t@users.noreply.github.com> Date: Fri, 23 Aug 2024 21:19:38 +0100 Subject: [PATCH] feature: add search results count to CodeMirror (#1498) --- .../components/CodeEditor/StyledWrapper.js | 18 +++++ .../src/components/CodeEditor/index.js | 73 ++++++++++++++++++- 2 files changed, 89 insertions(+), 2 deletions(-) diff --git a/packages/bruno-app/src/components/CodeEditor/StyledWrapper.js b/packages/bruno-app/src/components/CodeEditor/StyledWrapper.js index 232f964ae..dc37065a6 100644 --- a/packages/bruno-app/src/components/CodeEditor/StyledWrapper.js +++ b/packages/bruno-app/src/components/CodeEditor/StyledWrapper.js @@ -14,6 +14,24 @@ const StyledWrapper = styled.div` background: #d2d7db; } + .CodeMirror-dialog { + overflow: visible; + } + + #search-results-count { + display: inline-block; + position: absolute; + top: calc(100% + 1px); + right: 0; + border-width: 0 0 1px 1px; + border-style: solid; + border-color: ${(props) => props.theme.codemirror.border}; + padding: 0.1em 0.8em; + background-color: ${(props) => props.theme.codemirror.bg}; + color: rgb(102, 102, 102); + white-space: nowrap; + } + textarea.cm-editor { position: relative; } diff --git a/packages/bruno-app/src/components/CodeEditor/index.js b/packages/bruno-app/src/components/CodeEditor/index.js index af8cda247..6e3bf48dd 100644 --- a/packages/bruno-app/src/components/CodeEditor/index.js +++ b/packages/bruno-app/src/components/CodeEditor/index.js @@ -111,6 +111,7 @@ export default class CodeEditor extends React.Component { // unnecessary updates during the update lifecycle. this.cachedValue = props.value || ''; this.variables = {}; + this.searchResultsCountElementId = 'search-results-count'; this.lintOptions = { esversion: 11, @@ -157,8 +158,16 @@ export default class CodeEditor extends React.Component { this.props.onSave(); } }, - 'Cmd-F': 'findPersistent', - 'Ctrl-F': 'findPersistent', + 'Cmd-F': (cm) => { + cm.execCommand('findPersistent'); + this._bindSearchHandler(); + this._appendSearchResultsCount(); + }, + 'Ctrl-F': (cm) => { + cm.execCommand('findPersistent'); + this._bindSearchHandler(); + this._appendSearchResultsCount(); + }, 'Cmd-H': 'replace', 'Ctrl-H': 'replace', Tab: function (cm) { @@ -310,6 +319,8 @@ export default class CodeEditor extends React.Component { this.editor.off('change', this._onEdit); this.editor = null; } + + this._unbindSearchHandler(); } render() { @@ -346,4 +357,62 @@ export default class CodeEditor extends React.Component { } } }; + + /** + * Bind handler to search input to count number of search results + */ + _bindSearchHandler = () => { + const searchInput = document.querySelector('.CodeMirror-search-field'); + + if (searchInput) { + searchInput.addEventListener('input', this._countSearchResults); + } + }; + + /** + * Unbind handler to search input to count number of search results + */ + _unbindSearchHandler = () => { + const searchInput = document.querySelector('.CodeMirror-search-field'); + + if (searchInput) { + searchInput.removeEventListener('input', this._countSearchResults); + } + }; + + /** + * Append search results count to search dialog + */ + _appendSearchResultsCount = () => { + const dialog = document.querySelector('.CodeMirror-dialog.CodeMirror-dialog-top'); + + if (dialog) { + const searchResultsCount = document.createElement('span'); + searchResultsCount.id = this.searchResultsCountElementId; + dialog.appendChild(searchResultsCount); + + this._countSearchResults(); + } + }; + + /** + * Count search results and update state + */ + _countSearchResults = () => { + let count = 0; + + const searchInput = document.querySelector('.CodeMirror-search-field'); + + if (searchInput && searchInput.value.length > 0) { + const text = new RegExp(searchInput.value, 'gi'); + const matches = this.editor.getValue().match(text); + count = matches ? matches.length : 0; + } + + const searchResultsCountElement = document.querySelector(`#${this.searchResultsCountElementId}`); + + if (searchResultsCountElement) { + searchResultsCountElement.innerText = `${count} results`; + } + }; }