From f308fe71f98199a227484bd6aff9e9719b32bb1e Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sat, 29 Dec 2018 18:24:02 +0100 Subject: [PATCH] Mobile: Fixes #1082: Highlight correct keywords when doing a search --- CliClient/tests/StringUtils.js | 44 +++++++++++++++++++ ReactNativeClient/lib/MdToHtml.js | 19 +------- .../lib/services/SearchEngine.js | 3 +- ReactNativeClient/lib/string-utils.js | 17 ++++++- 4 files changed, 63 insertions(+), 20 deletions(-) create mode 100644 CliClient/tests/StringUtils.js diff --git a/CliClient/tests/StringUtils.js b/CliClient/tests/StringUtils.js new file mode 100644 index 0000000000..5e1b4b3b5d --- /dev/null +++ b/CliClient/tests/StringUtils.js @@ -0,0 +1,44 @@ +require('app-module-path').addPath(__dirname); + +const { time } = require('lib/time-utils.js'); +const { fileContentEqual, setupDatabase, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync } = require('test-utils.js'); +const StringUtils = require('lib/string-utils'); + +process.on('unhandledRejection', (reason, p) => { + console.log('Unhandled Rejection at: Promise', p, 'reason:', reason); +}); + +describe('StringUtils', function() { + + beforeEach(async (done) => { + done(); + }); + + it('should surround keywords with strings', async (done) => { + const testCases = [ + [['test'], 'test', 'a', 'b', 'atestb'], + [['test'], 'Test', 'a', 'b', 'aTestb'], + [['te[]st'], 'Te[]st', 'a', 'b', 'aTe[]stb'], + [['test1', 'test2'], 'bla test1 blabla test1 bla test2 not this one - test22', 'a', 'b', 'bla atest1b blabla atest1b bla atest2b not this one - test22'], + [['test1', 'test2'], 'bla test1 test1 bla test2', '', '', 'bla test1 test1 bla test2'], + [[{ type:'regex', value:'test.*?'}], 'bla test1 test1 bla test2 test tttest', 'a', 'b', 'bla atest1b atest1b bla atest2b atestb tttest'], + ]; + + for (let i = 0; i < testCases.length; i++) { + const t = testCases[i]; + + const keywords = t[0]; + const input = t[1]; + const prefix = t[2]; + const suffix = t[3]; + const expected = t[4]; + + const actual = StringUtils.surroundKeywords(keywords, input, prefix, suffix); + + expect(actual).toBe(expected); + } + + done(); + }); + +}); \ No newline at end of file diff --git a/ReactNativeClient/lib/MdToHtml.js b/ReactNativeClient/lib/MdToHtml.js index 6125fefa93..11774ce886 100644 --- a/ReactNativeClient/lib/MdToHtml.js +++ b/ReactNativeClient/lib/MdToHtml.js @@ -7,7 +7,7 @@ const { shim } = require('lib/shim.js'); const { _ } = require('lib/locale'); const md5 = require('md5'); const MdToHtml_Katex = require('lib/MdToHtml_Katex'); -const { pregQuote } = require('lib/string-utils.js'); +const StringUtils = require('lib/string-utils.js'); class MdToHtml { @@ -415,22 +415,7 @@ class MdToHtml { } applyHighlightedKeywords_(body, keywords) { - for (let i = 0; i < keywords.length; i++) { - const k = keywords[i]; - - let regexString = ''; - - if (k.type === 'regex') { - regexString = k.value; - } else { - regexString = pregQuote(k); - } - - const re = new RegExp('(^|\n|\b)(' + regexString + ')(\n|\b|$)', 'gi'); - body = body.replace(re, '$1$2$3'); - } - - return body; + return StringUtils.surroundKeywords(keywords, body, '', ''); } render(body, style, options = null) { diff --git a/ReactNativeClient/lib/services/SearchEngine.js b/ReactNativeClient/lib/services/SearchEngine.js index ce56e02453..a32d9313f2 100644 --- a/ReactNativeClient/lib/services/SearchEngine.js +++ b/ReactNativeClient/lib/services/SearchEngine.js @@ -108,7 +108,8 @@ class SearchEngine { let regexString = pregQuote(term); if (regexString[regexString.length - 1] === '*') { - regexString = regexString.substr(0, regexString.length - 2) + '[^' + pregQuote(' \t\n\r,.,+-*?!={}<>|:"\'()[]') + ']' + '*'; + // regexString = regexString.substr(0, regexString.length - 2) + '[^' + pregQuote(' \t\n\r,.,+-*?!={}<>|:"\'()[]') + ']' + '*'; + regexString = regexString.substr(0, regexString.length - 2) + '.*?'; } return regexString; diff --git a/ReactNativeClient/lib/string-utils.js b/ReactNativeClient/lib/string-utils.js index 27b378e300..955e31ff77 100644 --- a/ReactNativeClient/lib/string-utils.js +++ b/ReactNativeClient/lib/string-utils.js @@ -224,8 +224,21 @@ function escapeHtml(s) { .replace(/'/g, "'"); } -function pregQuote(str, delimiter) { +function pregQuote(str, delimiter = '') { return (str + '').replace(new RegExp('[.\\\\+*?\\[\\^\\]$(){}=!<>|:\\' + (delimiter || '') + '-]', 'g'), '\\$&'); } -module.exports = { removeDiacritics, escapeFilename, wrap, splitCommandString, padLeft, toTitleCase, escapeHtml, pregQuote }; \ No newline at end of file +function surroundKeywords(keywords, text, prefix, suffix) { + let regexString = keywords.map((k) => { + if (k.type === 'regex') { + return k.value; + } else { + return pregQuote(k); + } + }).join('|'); + regexString = '\\b(' + regexString + ')\\b' + const re = new RegExp(regexString, 'gi'); + return text.replace(re, prefix + '$1' + suffix); +} + +module.exports = { removeDiacritics, escapeFilename, wrap, splitCommandString, padLeft, toTitleCase, escapeHtml, pregQuote, surroundKeywords }; \ No newline at end of file