Wiring Search/Replace UI

This commit is contained in:
itdominator 2024-04-06 23:50:50 -05:00
parent 8b555991e4
commit 84b96ace5e
9 changed files with 311 additions and 65 deletions

View File

@ -63,4 +63,4 @@ class StylingMixin:
plural = "s" if total_count > 1 else "" plural = "s" if total_count > 1 else ""
if total_count == 0: self.update_style(2) if total_count == 0: self.update_style(2)
self._find_status_lbl.set_label(f"{count} results{plural} found for '{query}'") self._find_status_lbl.set_label(f"{count} result{plural} found for '{query}'")

View File

@ -123,17 +123,15 @@
</div> </div>
<div class="col col-5 line-height-32px"> <div class="col col-5 line-height-32px">
<button title="Close Panel" class="float-end" onclick="hideSearchReplace()">X</button> <button title="Close Panel" class="float-end btn btn-sm btn-dark" onclick="hideSearchReplace()">X</button>
<button title="Whole Word" class="float-end"> <button id="whole-word-btn" title="Whole Word" class="float-end btn btn-sm btn-dark">
<img src="resources/imgs/whole-word.png" /> <img src="resources/imgs/whole-word.png" />
</button> </button>
<button title="Only In Selection" class="float-end"> <button id="only-in-selection-btn" title="Only In Selection" class="float-end btn btn-sm btn-dark">
<img src="resources/imgs/only-in-selection.png" /> <img src="resources/imgs/only-in-selection.png" />
</button> </button>
<button title="Match Case" class="float-end">Aa</button> <button id="match-case-btn" title="Match Case" class="float-end btn btn-sm btn-dark">Aa</button>
<button id="use-regex-btn" title="Use Regex" class="float-end btn btn-sm btn-dark" btn>.*</button>
<button title="Use Regex" class="float-end">.*</button>
</div> </div>
</div> </div>
@ -141,34 +139,43 @@
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<input id="find-entry" class="sr-input-expand" type="search" <div class="input-group-sm mb-3">
title="Find in current buffer" <input id="find-entry"
placeholder="Find in current buffer" class="form-control"
/> type="search"
placeholder="Find in current buffer"
aria-label="Find in current buffer"
/>
</div>
</div> </div>
<div class="col col-auto"> <div class="col col-auto">
<button class="float-end width-8em">Find All</button> <button id="find-btn" class="width-8em btn btn-sm btn-dark">Find</button>
<button class="float-end width-8em">Find</button> <button id="find-all-btn" class="width-8em btn btn-sm btn-dark">Find All</button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="margin-tb-1em"></div>
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<input id="replace-entry" class="sr-input-expand" type="search" <div class="row">
title="Replace in current buffer" <div class="col">
placeholder="Replace in current buffer" <div class="input-group-sm mb-3">
/> <input id="replace-entry"
</div> class="form-control"
<div class="col col-auto"> type="search"
<button class="float-end width-8em">Replace All</button> title="Replace in current buffer"
<button class="float-end width-8em">Replace</button> placeholder="Replace in current buffer"
/>
</div>
</div>
<div class="col col-auto">
<button id="replace-btn" class="width-8em btn btn-sm btn-dark">Replace</button>
<button id="replace-all-btn" class="width-8em btn btn-sm btn-dark">Replace All</button>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -172,6 +172,26 @@
font-size: initial; font-size: initial;
} }
.searching,
.search-success,
.search-fail {
border-style: solid;
color: rgba(125, 125, 125, 1) !important;
}
.searching {
border-color: rgba(0, 225, 225, 0.64) !important;
}
.search-success {
background: rgba(136, 204, 39, 0.12) !important;
border-color: rgba(136, 204, 39, 1) !important;
}
.search-fail {
background: rgba(170, 18, 18, 0.12) !important;
border-color: rgba(200, 18, 18, 1) !important;
}
/* Other message text colors */ /* Other message text colors */
.error { color: rgb(170, 18, 18); } .error { color: rgb(170, 18, 18); }
.warning { color: rgb(255, 168, 0); } .warning { color: rgb(255, 168, 0); }

View File

@ -13,6 +13,16 @@ ul, li {
list-style: none; list-style: none;
} }
input.form-control,
input.form-control:focus,
input.form-control::after,
input.form-control::placeholder {
background-color: rgba(0, 0, 0, 0.0) !important;
color: rgba(255, 255, 255, 1.0) !important;
/*text-shadow: 0px 0px 0px black !important;*/
box-shadow: none !important;
}
.modal-header, .modal-header,
.modal-footer { .modal-footer {
background-color: rgba(0, 0, 0, 0.64); background-color: rgba(0, 0, 0, 0.64);

View File

@ -175,6 +175,13 @@ class InputCheckboxContainer extends HTMLElement {
} }
} }
const QueryState = {
Searching: 0,
SearchSuccess: 1,
SearchFail: 2
}
class SearchReplaceContainer extends HTMLElement { class SearchReplaceContainer extends HTMLElement {
constructor() { constructor() {
super(); super();
@ -186,16 +193,232 @@ class SearchReplaceContainer extends HTMLElement {
const shadowRoot = this.attachShadow({ mode: "open" }); const shadowRoot = this.attachShadow({ mode: "open" });
shadowRoot.appendChild( templateContent.cloneNode(true) ); shadowRoot.appendChild( templateContent.cloneNode(true) );
this.showing = false;
} }
loadSignals() { loadSignals() {
this.bindToggleSignal( this.shadowRoot.getElementById("whole-word-btn") );
this.bindToggleSignal( this.shadowRoot.getElementById("only-in-selection-btn") );
this.bindToggleSignal( this.shadowRoot.getElementById("match-case-btn") );
this.bindToggleSignal( this.shadowRoot.getElementById("use-regex-btn") );
let elm = this.shadowRoot.getElementById("find-entry"); let elm = this.shadowRoot.getElementById("find-entry");
elm.addEventListener("keyup", (eve) => { elm.addEventListener("keyup", (eve) => {
findEntry(eve.value); if (eve.key === "Enter") {
let elm = this.shadowRoot.getElementById("find-btn");
elm.click();
return
}
let elm = this.shadowRoot.getElementById("find-all-btn");
elm.click();
});
elm = this.shadowRoot.getElementById("find-btn");
elm.addEventListener("click", (eve) => {
this.findEntry( this.getQuery() );
});
elm = this.shadowRoot.getElementById("find-all-btn");
elm.addEventListener("click", (eve) => {
this.findAllEntries( this.getQuery() );
});
elm = this.shadowRoot.getElementById("replace-btn");
elm.addEventListener("click", (eve) => {
this.findEntry( this.getQuery() );
this.replaceEntry( this.getreplacer() );
});
elm = this.shadowRoot.getElementById("replace-all-btn");
elm.addEventListener("click", (eve) => {
this.findEntry( this.getQuery() );
this.replaceAll( this.getreplacer() );
}); });
} }
bindToggleSignal(elm) {
elm.addEventListener("click", (eve) => {
let elm = eve.target.nodeName === "IMG" ? eve.target.parentElement : eve.target;
let isActive = elm.classList.contains("btn-info");
if (isActive) {
elm.classList.remove("btn-info");
elm.classList.add("btn-dark");
} else {
elm.classList.add("btn-info");
elm.classList.remove("btn-dark")
}
this.setFindOptionsLbl();
});
}
toggleShow() {
if (this.showing) {
this.showing = false;
$('#bottom-gutter').popover('hide');
} else {
this.showing = true;
$('#bottom-gutter').popover('show');
}
setTimeout(() => {
if (this.showing) {
let elm = this.shadowRoot.getElementById("find-entry");
elm.focus();
} else {
editor.focus();
}
}, 0.5);
}
findPreviousEntry(query) {
editor.findPrevious();
}
replaceEntry(toStr) {
editor.replace(toStr);
}
replaceAll(toStr) {
editor.replaceAll(toStr);
}
findNextEntry(query) {
editor.findNext();
}
findAllEntries(query = null, isBackwwards = true, isWrap = true, range = null) {
this.updateStyle(QueryState.SearchSuccess);
if (query === "") {
this.shadowRoot.getElementById("find-status-lbl").innerText = "Find in current buffer";
this.updateStyle(QueryState.Searching);
this.clearSearchMarkers();
return;
}
let totalCount = editor.findAll(query, {
backwards: isBackwwards === "True" ? true : false,
wrap: isWrap === "True" ? true : false,
caseSensitive: this.isMatchCase(),
wholeWord: this.isUseWholeWord(),
regExp: this.isUseRegex(),
range: range === "True" ? true : false
});
if (totalCount === 0) {
console.log('Empty search result...');
this.clearSearchMarkers();
}
this.updateStatusLbl(totalCount, query);
return totalCount;
}
clearSearchMarkers() {
let markers = session.getMarkers(false);
for (var id in markers) {
if (
markers[id].clazz.indexOf("ace_selection") === 0 ||
markers[id].clazz.indexOf("ace_selected-word") === 0
) {
session.removeMarker(id);
}
}
}
findEntry(query = null, isBackwwards = true, isWrap = true, range = null) {
let result = editor.find(query, {
backwards: isBackwwards === "True" ? true : false,
wrap: isWrap === "True" ? true : false,
caseSensitive: this.isMatchCase(),
wholeWord: this.isUseWholeWord(),
regExp: this.isUseRegex(),
range: range === "True" ? true : false
});
return result;
}
updateStatusLbl(totalCount = 0, query = "") {
if ( !query ) return;
let count = (totalCount > 0) ? totalCount : "No";
let plural = (totalCount > 1) ? "s" : "";
if (totalCount === 0)
this.updateStyle(QueryState.SearchFail);
const statusLbl = `${count} result${plural} found for '${query}'`;
this.shadowRoot.getElementById("find-status-lbl").innerText = statusLbl;
}
setFindOptionsLbl() {
let findOptions = "Finding with Options: ";
if ( this.isUseRegex() )
findOptions += "Regex";
findOptions += ( this.isUseRegex() ) ? ", " : "";
findOptions += ( this.isMatchCase() ) ? "Case Sensitive" : "Case Inensitive";
if ( this.isSelectionSearchOnly() )
findOptions += ", Within Current Selection";
if ( this.isUseWholeWord() )
findOptions += ", Whole Word";
this.shadowRoot.getElementById("find-options-lbl").innerText = findOptions;
}
updateStyle(state) {
let elm = this.shadowRoot.getElementById("find-entry");
elm.classList.remove("searching")
elm.classList.remove("search-success")
elm.classList.remove("search-fail")
if (state === 0)
elm.classList.add("searching");
else if (state === 1)
elm.classList.add("search-success");
else if (state === 2)
elm.classList.add("search-fail");
}
getQuery() {
return this.shadowRoot.getElementById("find-entry").value;
}
getreplacer() {
return this.shadowRoot.getElementById("replace-entry").value;
}
isUseWholeWord() {
let elm = this.shadowRoot.getElementById("whole-word-btn");
return elm.classList.contains("btn-info");
}
isSelectionSearchOnly() {
let elm = this.shadowRoot.getElementById("only-in-selection-btn");
return elm.classList.contains("btn-info");
}
isMatchCase() {
let elm = this.shadowRoot.getElementById("match-case-btn");
return elm.classList.contains("btn-info");
}
isUseRegex() {
let elm = this.shadowRoot.getElementById("use-regex-btn");
return elm.classList.contains("btn-info");
}
} }

View File

@ -37,8 +37,8 @@ const loadLSPClientJSFiles = () => {
} }
const loadSearchFind = () => { const loadSearchFind = () => {
let elm = document.createElement("search-replace"); searchReplace = document.createElement("search-replace");
let options = {container: "html", content: elm, html: true}; let options = {container: "html", content: searchReplace, html: true};
$('#bottom-gutter').popover(options); $('#bottom-gutter').popover(options);
} }
@ -57,6 +57,11 @@ window.onerror = function(msg, url, line, col, error) {
document.addEventListener("keyup", (eve) => { document.addEventListener("keyup", (eve) => {
if (blockHigherNewtonEvePropigation) {
blockHigherNewtonEvePropigation = false;
return;
}
switch (eve.key) { switch (eve.key) {
case "ArrowUp": case "ArrowUp":
setLabels(); setLabels();
@ -96,6 +101,11 @@ document.addEventListener("keyup", (eve) => {
} }
} }
break; break;
case "f":
if (searchReplace.showing) {
searchReplace.toggleShow();
}
break
default: default:
setLabels(); setLabels();
break break
@ -104,6 +114,8 @@ document.addEventListener("keyup", (eve) => {
document.addEventListener("keydown", (eve) => { document.addEventListener("keydown", (eve) => {
if (blockHigherNewtonEvePropigation) return;
switch (eve.key) { switch (eve.key) {
case "ArrowUp": case "ArrowUp":
if ( isNotNullOrUndefined(previewSel) ) { if ( isNotNullOrUndefined(previewSel) ) {

View File

@ -2,6 +2,7 @@ const messenger = (window.webkit) ? window.webkit.messageHandlers : (message) =
console.log("Message: " + message); console.log("Message: " + message);
}; };
const EDITOR_OPTS = { const EDITOR_OPTS = {
printMarginColumn: 80, printMarginColumn: 80,
enableBasicAutocompletion: true, enableBasicAutocompletion: true,
@ -17,6 +18,7 @@ const EDITOR_OPTS = {
mergeUndoDeltas: false mergeUndoDeltas: false
} }
const BASE_LINK = `${window.location.href}resources/js/libs/ace_editor/lsp`; const BASE_LINK = `${window.location.href}resources/js/libs/ace_editor/lsp`;
const LSP_SERVER_CONFG = `${window.location.href}../lsp-servers-config.json`; const LSP_SERVER_CONFG = `${window.location.href}../lsp-servers-config.json`;
const BASE_LSP_LINK = "http://0.0.0.0:4880"; const BASE_LSP_LINK = "http://0.0.0.0:4880";
@ -27,6 +29,7 @@ let lspServersConfig = null;
let lspSettingsUI = document.getElementById('lsp-settings'); let lspSettingsUI = document.getElementById('lsp-settings');
let searchReplace = null;
let editor = null; let editor = null;
let previewEditor = null; let previewEditor = null;
let aceSessions = {}; let aceSessions = {};
@ -36,3 +39,6 @@ let fontSize = 12;
let highlightLine = true; let highlightLine = true;
let isControlDown = false; let isControlDown = false;
let queryMarkers = []; let queryMarkers = [];
let blockHigherNewtonEvePropigation = false;

View File

@ -29,9 +29,8 @@ const editorCommands = [
name: "search", name: "search",
bindKey: {win: "ctrl-f", mac: "ctrl-f"}, bindKey: {win: "ctrl-f", mac: "ctrl-f"},
exec: function(editor) { exec: function(editor) {
// let selectedStr = session.doc.getTextRange(editor.getSelectionRange()); blockHigherNewtonEvePropigation = true;
$('#bottom-gutter').popover('toggle') searchReplace.toggleShow();
// sendMessage("tggl_search_replace", "", "", "", selectedStr);
}, },
readOnly: true readOnly: true
}, { }, {

View File

@ -221,40 +221,6 @@ const setLabels = () => {
} }
const findEntry = (query = null, isBackwwards = true, isWrap = true,
isCaseSensitive = false,
useWholeWord = false,
useRegExp = false,
range = null) => {
// if ( isNotNullOrUndefined(queryMarkers) ) {
// for (let i = 0; i < queryMarkers.length; i++) {
// delete queryMarkers[i];
// }
// }
// let result = editor.find(query, {
// backwards: isBackwwards === "True" ? true : false,
// wrap: isWrap === "True" ? true : false,
// caseSensitive: isCaseSensitive === "True" ? true : false,
// wholeWord: useWholeWord === "True" ? true : false,
// regExp: useRegExp === "True" ? true : false,
// range: range === "True" ? true : false
// });
let result = editor.findAll(query, {
caseSensitive: isCaseSensitive === "True" ? true : false,
wholeWord: useWholeWord === "True" ? true : false,
regExp: useRegExp === "True" ? true : false,
});
console.log(result)
// if ( isNotNullOrUndefined(result) ) {
// for (let i = 0; i < result.length; i++) {
// loadMarker( result[i] );
// }
// }
}
const loadMarker = (r) => { const loadMarker = (r) => {
var range = new Range(rowStart, columnStart, rowEnd, columnEnd); var range = new Range(rowStart, columnStart, rowEnd, columnEnd);
@ -264,6 +230,9 @@ const loadMarker = (r) => {
} }
const findAllEntries = (query) => {
editor.findAll();
}
const findNextEntry = (query) => { const findNextEntry = (query) => {
editor.findNext(); editor.findNext();