Add regex error checking, and display a message to the user when their regular expression has a syntax error. Additionally, use a non-capturing group to surround the user input when `Match whole word` is enabled in case alternates are being used. Finally, add a safety check to highlighting to avoid an infinite loop when zero-length matches happen.
This commit is contained in:
parent
e7fd95aafd
commit
446205c7bd
|
@ -406,6 +406,12 @@ else if (log?.IsValid == true)
|
||||||
<span role="button" v-bind:class="{ active: !filterInsensitive }" v-on:click="toggleFilterInsensitive" title="Match exact capitalization only.">aA</span>
|
<span role="button" v-bind:class="{ active: !filterInsensitive }" v-on:click="toggleFilterInsensitive" title="Match exact capitalization only.">aA</span>
|
||||||
<span role="button" v-bind:class="{ active: filterUseWord, 'whole-word': true }" v-on:click="toggleFilterWord" title="Match whole word only."><i>“ ”</i></span>
|
<span role="button" v-bind:class="{ active: filterUseWord, 'whole-word': true }" v-on:click="toggleFilterWord" title="Match whole word only."><i>“ ”</i></span>
|
||||||
<span role="button" v-bind:class="{ active: shouldHighlight }" v-on:click="toggleHighlight" title="Highlight matches in the log text.">HL</span>
|
<span role="button" v-bind:class="{ active: shouldHighlight }" v-on:click="toggleHighlight" title="Highlight matches in the log text.">HL</span>
|
||||||
|
<div
|
||||||
|
v-if="filterError"
|
||||||
|
class="filter-error"
|
||||||
|
>
|
||||||
|
{{ filterError }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<filter-stats
|
<filter-stats
|
||||||
v-bind:start="start"
|
v-bind:start="start"
|
||||||
|
|
|
@ -187,6 +187,11 @@ table caption {
|
||||||
margin-top: 0.5em;
|
margin-top: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#filters .filter-error {
|
||||||
|
color: #880000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#filters .filter-error,
|
||||||
#filters .stats {
|
#filters .stats {
|
||||||
margin-top: 0.5em;
|
margin-top: 0.5em;
|
||||||
font-size: 0.75em;
|
font-size: 0.75em;
|
||||||
|
@ -210,7 +215,7 @@ table caption {
|
||||||
|
|
||||||
@media (max-width: 1019px) {
|
@media (max-width: 1019px) {
|
||||||
#filters:not(.sticky) {
|
#filters:not(.sticky) {
|
||||||
width: calc(100vw - 3em);
|
width: calc(100vw - 5em);
|
||||||
}
|
}
|
||||||
|
|
||||||
#filters {
|
#filters {
|
||||||
|
|
|
@ -247,7 +247,8 @@ smapi.logParser = function (state) {
|
||||||
// add the properties we're passing to Vue
|
// add the properties we're passing to Vue
|
||||||
state.totalMessages = state.messages.length;
|
state.totalMessages = state.messages.length;
|
||||||
state.filterText = "";
|
state.filterText = "";
|
||||||
state.filterRegex = "";
|
state.filterRegex = null;
|
||||||
|
state.filterError = null;
|
||||||
state.showContentPacks = true;
|
state.showContentPacks = true;
|
||||||
state.useHighlight = true;
|
state.useHighlight = true;
|
||||||
state.useRegex = false;
|
state.useRegex = false;
|
||||||
|
@ -506,6 +507,12 @@ smapi.logParser = function (state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
index = match.index + match[0].length;
|
index = match.index + match[0].length;
|
||||||
|
|
||||||
|
// In the event of a zero-length match, forcibly increment
|
||||||
|
// the last index of the regular expression to ensure we
|
||||||
|
// aren't stuck in an infinite loop.
|
||||||
|
if (match[0].length == 0)
|
||||||
|
filter.lastIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add any trailing text after the last match was found.
|
// Add any trailing text after the last match was found.
|
||||||
|
@ -857,14 +864,30 @@ smapi.logParser = function (state) {
|
||||||
if (!text || !text.length) {
|
if (!text || !text.length) {
|
||||||
this.filterText = "";
|
this.filterText = "";
|
||||||
this.filterRegex = null;
|
this.filterRegex = null;
|
||||||
|
this.filterError = null;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!state.useRegex)
|
if (!state.useRegex)
|
||||||
text = helpers.escapeRegex(text);
|
text = helpers.escapeRegex(text);
|
||||||
this.filterRegex = new RegExp(
|
|
||||||
state.useWord ? `\\b${text}\\b` : text,
|
const flags = state.useInsensitive ? "ig" : "g";
|
||||||
state.useInsensitive ? "ig" : "g"
|
|
||||||
);
|
this.filterError = null;
|
||||||
|
let regex;
|
||||||
|
|
||||||
|
try {
|
||||||
|
regex = new RegExp(text, flags);
|
||||||
|
} catch (err) {
|
||||||
|
regex = null;
|
||||||
|
this.filterError = err.message;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (regex)
|
||||||
|
this.filterRegex = state.useWord ?
|
||||||
|
new RegExp(`\\b(?:${text})\\b`, flags) :
|
||||||
|
regex;
|
||||||
|
else
|
||||||
|
this.filterRegex = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateUrl();
|
this.updateUrl();
|
||||||
|
|
Loading…
Reference in New Issue