Updates to JS and multiple results to handle more regex

This commit is contained in:
mattpass
2021-04-09 16:07:41 +01:00
parent 1cad4b074c
commit 01df964ac7
2 changed files with 109 additions and 67 deletions

View File

@@ -2794,8 +2794,8 @@ var ICEcoder = {
// FIND & REPLACE
// ==============
// Backslash escape regex chars in string
escapeRegExp: function(string) {
// Backslash escape regex special chars in string
escapeRegex: function(string) {
// $& means the whole matched string
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
},
@@ -2829,81 +2829,43 @@ var ICEcoder = {
// Find & replace text according to user selections
findReplace: function(find, selectNext, canActionChanges, findPrevious) {
let replace, results, thisCM, avgBlockH, addPadding, rBlocks, haveMatch, blockColor, replaceQS, targetQS, filesQS;
let replace, results, thisCM, thisSelection, rBlocks, replaceQS, targetQS, filesQS;
// Determine our find rExp, replace value and results display
const rExp = new RegExp(true === parent.ICEcoder.findRegex ? find : ICEcoder.escapeRegExp(find), "gi");
const rExp = new RegExp(true === parent.ICEcoder.findRegex ? find : ICEcoder.escapeRegex(find), "gi");
replace = get('replace').value;
results = get('results');
// Get CM pane
thisCM = this.getThisCM();
// Get this selection, either as regex escaped version or regular, for comparisons
thisSelection = true === parent.ICEcoder.findRegex ? ICEcoder.escapeRegex(thisCM.getSelection()) : thisCM.getSelection();
// Finding in this document only
if (thisCM && 0 < find.length && t['this document'] === document.findAndReplace.target.value) {
// Replacing?
if (t['and'] === document.findAndReplace.connector.value && true === canActionChanges) {
// Find & replace the next instance, or all?
if (t['replace'] === document.findAndReplace.replaceAction.value && thisCM.getSelection().toLowerCase() === find.toLowerCase()) {
if (t['replace'] === document.findAndReplace.replaceAction.value && thisSelection.toLowerCase() === find.toLowerCase()) {
thisCM.replaceSelection(replace, "around");
} else if (t['replace all'] === document.findAndReplace.replaceAction.value) {
thisCM.setValue(thisCM.getValue().replace(rExp, replace));
}
}
// Set results, resultsLines and findResult back to defaults
this.results = [];
this.resultsLines = [];
this.findResult = 0;
// Start new iterators for line & last line
let i = 0;
let lastLine = -1;
// Get lineNum and chNum from cursor
const lineNum = thisCM.getCursor(true === selectNext ? "anchor" : "head").line + 1;
const chNum = thisCM.getCursor(true === selectNext ? "anchor" : "head").ch;
// Work out the avg block is either line height or fraction of space available
avgBlockH = !this.scrollBarVisible ? thisCM.defaultTextHeight() : parseInt(this.content.style.height, 10) / thisCM.lineCount();
// Need to add padding if there's no scrollbar, so current line highlighting lines up with it
addPadding = !this.scrollBarVisible ? thisCM.heightAtLine(0) : 0;
// Result blocks string empty to start, ready to hold DOM elems to show in results bar
rBlocks = "";
// Start looking for results
thisCM.eachLine(function(line) {
i++;
haveMatch = false;
// If we have matches for our regex for this line
while ((match = rExp.exec(line.text)) !== null) {
haveMatch = true;
// Not the same as last line, add to resultsLines
if (lastLine !== i) {
ICEcoder.resultsLines.push(match.index);
lastLine = i;
}
// If the line containing a result is less than than the cursors line or
// if the character position of the match is less than the cursor position, increment findResult
if (i < lineNum || (i === lineNum && match.index < chNum)) {
ICEcoder.findResult++;
}
// Push the line & char position coords into results
ICEcoder.results.push([i, match.index]);
}
// If the avg block height for results in results bar is above 0.5 pixels high, we can add a DOM elem
if (0.5 <= avgBlockH) {
// Red for current line, grey for another line, transparent if no match
blockColor = haveMatch ? thisCM.getCursor().line + 1 == i ? "rgba(192,0,0,0.3)" : "rgba(128,128,128,0.3)" : "transparent";
// Add the DOM elem into our rBlocks string
rBlocks += '<div style="position: absolute; display: block; width: 12px; height:' + avgBlockH + 'px; background: ' + blockColor + '; top: ' + parseInt((avgBlockH * (i - 1)) + addPadding, 10) + 'px"></div>';
}
});
rData = ICEcoder.findInCMContent(thisCM, rExp, selectNext);
// Set results, resultsLines and findResult plus rBlocks which shows DOM elems in results bar
this.results = rData.results;
this.resultsLines = rData.resultsLines;
this.findResult = rData.findResult;
rBlocks = rData.rBlocks;
// Increment findResult one more if our selection is what we want to find and we want to find next
if (find.toLowerCase() === thisCM.getSelection().toLowerCase() && false === findPrevious) {
ICEcoder.findResult++;
if (find.toLowerCase() === thisSelection.toLowerCase() && false === findPrevious) {
this.findResult++;
}
if (findPrevious) {
@@ -2940,9 +2902,11 @@ var ICEcoder = {
this.goToLine(this.results[this.findResult][0], this.results[this.findResult][1], true);
// Finally, highlight our selection and focus on CM pane
// Note when setting the end of the selection we need to deduct extra chars added (the regex escaping backslashes)
// TODO: This idea doesn't really work if you say have "^\$x" and $x's in docs
thisCM.setSelection(
{"line": this.results[this.findResult][0]-1, "ch": this.results[this.findResult][1]},
{"line": this.results[this.findResult][0]-1, "ch": this.results[this.findResult][1] + find.length}
{"line": this.results[this.findResult][0]-1, "ch": this.results[this.findResult][1] + find.length - parseInt((ICEcoder.escapeRegex(find).length - find.length) / 2, 10)}
);
this.focus();
}
@@ -3003,6 +2967,67 @@ var ICEcoder = {
}
},
findInCMContent: function(thisCM, rExp, selectNext) {
let avgBlockH, addPadding, rBlocks, blockColor, haveMatch;
// Start new iterators for line & last line
let i = 0;
let lastLine = -1;
// Set results, resultsLines and findResult to defaults
let results = [];
let resultsLines = [];
let findResult = 0;
// Get lineNum and chNum from cursor
const lineNum = thisCM.getCursor(true === selectNext ? "anchor" : "head").line + 1;
const chNum = thisCM.getCursor(true === selectNext ? "anchor" : "head").ch;
// Work out the avg block is either line height or fraction of space available
avgBlockH = !this.scrollBarVisible ? thisCM.defaultTextHeight() : parseInt(this.content.style.height, 10) / thisCM.lineCount();
// Need to add padding if there's no scrollbar, so current line highlighting lines up with it
addPadding = !this.scrollBarVisible ? thisCM.heightAtLine(0) : 0;
// Result blocks string empty to start, ready to hold DOM elems to show in results bar
rBlocks = "";
thisCM.eachLine(function(line) {
i++;
haveMatch = false;
// If we have matches for our regex for this line
while ((match = rExp.exec(line.text)) !== null) {
haveMatch = true;
// Not the same as last line, add to resultsLines
if (lastLine !== i) {
resultsLines.push(match.index);
lastLine = i;
}
// If the line containing a result is less than than the cursors line or
// if the character position of the match is less than the cursor position, increment findResult
if (i < lineNum || (i === lineNum && match.index < chNum)) {
findResult++;
}
// Push the line & char position coords into results
results.push([i, match.index]);
}
// If the avg block height for results in results bar is above 0.5 pixels high, we can add a DOM elem
if (0.5 <= avgBlockH) {
// Red for current line, grey for another line, transparent if no match
blockColor = haveMatch ? thisCM.getCursor().line + 1 == i ? "rgba(192,0,0,0.3)" : "rgba(128,128,128,0.3)" : "transparent";
// Add the DOM elem into our rBlocks string
rBlocks += '<div style="position: absolute; display: block; width: 12px; height:' + avgBlockH + 'px; background: ' + blockColor + '; top: ' + parseInt((avgBlockH * (i - 1)) + addPadding, 10) + 'px"></div>';
}
});
return {
"results": results,
"resultsLines": resultsLines,
"findResult": findResult,
"rBlocks": rBlocks
}
},
// Replace text in a file
replaceInFile: function(fileRef, find, replace) {
this.serverQueue(

View File

@@ -48,24 +48,27 @@ if (true === isset($_GET['target']) && false !== strpos($_GET['target'], "filena
let foundInSelected = false;
const userTarget = parent.document.findAndReplace.target.value;
const findText = parent.document.findAndReplace.find.value;
const rExp = new RegExp(true === parent.ICEcoder.findRegex ? findText : parent.ICEcoder.escapeRegex(findText), "gi");
<?php
$findText = str_replace("ICEcoder:", "", str_replace("&#39;", "\'", $_GET['find']));
// Find in open docs?
// TODO: This doesn't actually replace if using regex, it doesn't error - tabs show a change, but nothing replaced
if (false === isset($_GET['target'])) {
$targetName = $t['document'];
?>
let startTab = parent.ICEcoder.selectedTab;
const rExp = new RegExp(findText, "gi");
for (let i = 1; i <= parent.ICEcoder.openFiles.length; i++) {
parent.ICEcoder.switchTab(i);
const cM = parent.ICEcoder.getcMInstance();
const content = cM.getValue();
if (content.match(rExp)) {
const selectNext = true;
rData = parent.ICEcoder.findInCMContent(cM, rExp, selectNext);
if (0 < rData.results.length) {
resultsDisplay +=
'<a href="javascript:gotoTab(' + i + '); goFind()">' +
parent.ICEcoder.openFiles[i - 1] +
'</a><br><div id="foundCount' + i + '"><?php echo $t['Found'];?> ' +
content.match(rExp).length +
rData.results.length +
' <?php echo $t['times'];?></div>';
<?php if (isset($_GET['replace'])) { ?>
resultsDisplay +=
@@ -79,8 +82,9 @@ if (true === isset($_GET['target']) && false !== strpos($_GET['target'], "filena
parent.ICEcoder.switchTab(startTab);
}
<?php
// Find in files or filenames
// Find in files or filenames
} else {
// filenames
if (0 < strpos($_GET['target'], "filenames")) {
$targetName = $t['file folder'];
?>
@@ -88,11 +92,18 @@ if (true === isset($_GET['target']) && false !== strpos($_GET['target'], "filena
for (let i = 0; i < spansArray.length; i++) {
let foundInSelected = false;
const targetURL = spansArray[i].id.replace(/\|/g, "/").toLowerCase();
const targetName = targetURL.substring(targetURL.lastIndexOf("/") + 1);
let haveMatch = false;
while ((match = rExp.exec(targetName)) !== null) {
console.log(match);
haveMatch = true;
}
if (
targetURL.lastIndexOf(findText.toLowerCase()) > targetURL.lastIndexOf("/")
&& -1 < targetURL.indexOf(findText.toLowerCase()) && targetURL.indexOf('_perms')>-1) {
// TODO: Find in filenames not working with regex, see all instances of findText and $findText below
true === haveMatch && -1 < targetURL.indexOf('_perms')) {
if (-1 < userTarget.indexOf("selected")) {
for (let j = 0; j < parent.ICEcoder.selectedFiles.length; j++) {
// TODO: This whole file needs comments - what does the below do?!
if (
0 === targetURL.replace(/\//g, "|").indexOf(parent.ICEcoder.selectedFiles[j].replace(/\//g, "|").replace(/_perms/g, ""))
&& (
@@ -110,6 +121,7 @@ if (true === isset($_GET['target']) && false !== strpos($_GET['target'], "filena
'\');parent.ICEcoder.goFindAfterOpenInt = setInterval(function(){goFindAfterOpen(\'<?php echo $docRoot;?>' +
targetURL.replace(/\|/g, "/").replace(/_perms/g, "") +
'\')}, 20);parent.ICEcoder.showHide(\'hide\', parent.document.getElementById(\'blackMask\'))">';
// TODO: get this line working
resultsDisplay +=
targetURL.replace(/\|/g, "/").replace(/_perms/g, "").replace(/<?php
echo str_replace("/", "\/",strtolower($findText)); ?>/g, "<b>" +
@@ -118,6 +130,7 @@ if (true === isset($_GET['target']) && false !== strpos($_GET['target'], "filena
<?php if (false === isset($_GET['replace'])) { ?>
resultsDisplay += '<div id="foundCount' + i +'">' + spansArray[i].innerHTML + '</div>';
<?php ;} else { ?>
// TODO: get this line working
resultsDisplay +=
'<div id="foundCount' + i + '">' + spansArray[i].innerHTML +
', <?php echo $t['rename to'];?> ' +
@@ -135,6 +148,7 @@ if (true === isset($_GET['target']) && false !== strpos($_GET['target'], "filena
}
}
<?php
// files
} else {
$targetName = $t['file'];
$r = 0;
@@ -192,6 +206,7 @@ if (true === isset($_GET['target']) && false !== strpos($_GET['target'], "filena
return $ret;
}
// TODO: consider $findText here
$results = phpGrep($findText, $docRoot . $iceRoot, $docRoot . $iceRoot);
echo 'resultsDisplay += "' . $results . '";';
?>
@@ -237,7 +252,8 @@ if (true === isset($_GET['target']) && false !== strpos($_GET['target'], "filena
};
const replaceInFileSingle = function(fileRef) {
parent.ICEcoder.replaceInFile(fileRef, findText, '<?php if (isset($_GET['replace'])) {echo $_GET['replace'];}; ?>');
// TODO: findText in this line
parent.ICEcoder.replaceInFile(fileRef, true === parent.ICEcoder.findRegex ? findText : parent.ICEcoder.escapeRegex(findText), '<?php if (isset($_GET['replace'])) {echo $_GET['replace'];}; ?>');
};
const replaceInFilesAll = function() {
@@ -249,7 +265,8 @@ if (true === isset($_GET['target']) && false !== strpos($_GET['target'], "filena
const renameSingle = function(arrayRef) {
fileRef = spansArray[arrayRef].id.replace(/\|/g, "/").replace(/_perms/g, "");
const rExp = new RegExp(findText, "gi");
const rExp = new RegExp(true === parent.ICEcoder.findRegex ? findText : parent.ICEcoder.escapeRegex(findText), "gi");
// TODO: get this working
newName = spansArray[arrayRef].id.replace(/\|/g, "/").replace(/_perms/g, "").replace(rExp, "<?php if (isset($_GET['replace'])) {echo $_GET['replace'];}; ?>");
parent.ICEcoder.renameFile(fileRef,newName);
};
@@ -277,7 +294,7 @@ if (true === isset($_GET['target']) && false !== strpos($_GET['target'], "filena
parent.document.getElementById('results').style.display = 'inline-block';
// Action the find and then focus on find input box
setTimeout(function() {
parent.ICEcoder.findReplace(findText, true, false, false);
parent.ICEcoder.findReplace(true === parent.ICEcoder.findRegex ? findText : parent.ICEcoder.escapeRegex(findText), true, false, false);
parent.document.getElementById("find").focus();
}, 0);
};