diff --git a/js/spell_check.js b/js/spell_check.js index 5fdbabf99..01ff46a4f 100644 --- a/js/spell_check.js +++ b/js/spell_check.js @@ -4,10 +4,12 @@ const electron = require('electron'); -const osLocale = require('os-locale'); +const Typo = require('typo-js'); +const fs = require('fs'); const os = require('os'); +const osLocale = require('os-locale'); +const path = require('path'); const semver = require('semver'); -const spellchecker = require('spellchecker'); const { remote, webFrame } = electron; @@ -40,6 +42,8 @@ function setupLinux(locale) { // apt-get install hunspell- can be run for easy access // to other dictionaries const location = process.env.HUNSPELL_DICTIONARIES || '/usr/share/hunspell'; + const affDataPath = path.join(location, `${locale}.aff`); + const dicDataPath = path.join(location, `${locale}.dic`); window.log.info( 'Detected Linux. Setting up spell check with locale', @@ -47,30 +51,20 @@ function setupLinux(locale) { 'and dictionary location', location ); - spellchecker.setDictionary(locale, location); - } else { - window.log.info( - 'Detected Linux. Using default en_US spell check dictionary' - ); - } -} -function setupWin7AndEarlier(locale) { - if (process.env.HUNSPELL_DICTIONARIES || locale !== 'en_US') { - const location = process.env.HUNSPELL_DICTIONARIES; + if (fs.existsSync(affDataPath) && fs.existsSync(dicDataPath)) { + const affData = fs.readFileSync(affDataPath, 'utf-8'); + const dicData = fs.readFileSync(dicDataPath, 'utf-8'); - window.log.info( - 'Detected Windows 7 or below. Setting up spell-check with locale', - locale, - 'and dictionary location', - location - ); - spellchecker.setDictionary(locale, location); - } else { - window.log.info( - 'Detected Windows 7 or below. Using default en_US spell check dictionary' - ); + return new Typo(locale, affData, dicData); + } + + window.log.error(`Could not find one of ${affDataPath} or ${dicDataPath} on filesystem`); } + + window.log.info('Detected Linux. Using default en_US spell check dictionary'); + + return new Typo(locale); } // We load locale this way and not via app.getLocale() because this call returns @@ -83,11 +77,12 @@ if (!process.env.LANG) { process.env.LANG = locale; } +let spellchecker = null; + if (process.platform === 'linux') { - setupLinux(locale); -} else if (process.platform === 'windows' && semver.lt(os.release(), '8.0.0')) { - setupWin7AndEarlier(locale); + spellchecker = setupLinux(locale); } else { + spellchecker = new Typo(locale); // OSX and Windows 8+ have OS-level spellcheck APIs window.log.info( 'Using OS-level spell check API with locale', @@ -101,7 +96,7 @@ const simpleChecker = { callback(mispelled); }, isMisspelled(word) { - const misspelled = spellchecker.isMisspelled(word); + const misspelled = !spellchecker.check(word); // The idea is to make this as fast as possible. For the many, many calls which // don't result in the red squiggly, we minimize the number of checks. @@ -117,11 +112,9 @@ const simpleChecker = { return true; }, getSuggestions(text) { - return spellchecker.getCorrectionsForMisspelling(text); - }, - add(word) { - spellchecker.add(word); + return spellchecker.suggest(text); }, + add() {}, }; const dummyChecker = { diff --git a/package.json b/package.json index ea58c1bfa..578969791 100644 --- a/package.json +++ b/package.json @@ -132,12 +132,12 @@ "sanitize.css": "11.0.0", "semver": "5.4.1", "sharp": "0.23.0", - "spellchecker": "3.7.0", "tar": "4.4.8", "testcheck": "1.0.0-rc.2", "tmp": "0.0.33", "to-arraybuffer": "1.0.1", "typeface-inter": "3.10.0", + "typo-js": "1.1.0", "underscore": "1.9.0", "uuid": "3.3.2", "websocket": "1.0.28" diff --git a/patches/typo-js+1.1.0.patch b/patches/typo-js+1.1.0.patch new file mode 100644 index 000000000..99c4e9321 --- /dev/null +++ b/patches/typo-js+1.1.0.patch @@ -0,0 +1,21 @@ +diff --git a/node_modules/typo-js/typo.js b/node_modules/typo-js/typo.js +index 68c285b..11710a1 100644 +--- a/node_modules/typo-js/typo.js ++++ b/node_modules/typo-js/typo.js +@@ -431,7 +431,7 @@ Typo.prototype = { + dictionaryTable[word] = null; + } + +- if (rules.length > 0) { ++ if (rules && rules.length > 0) { + if (dictionaryTable[word] === null) { + dictionaryTable[word] = []; + } +@@ -546,6 +546,7 @@ Typo.prototype = { + else if (this.flags.FLAG === "num") { + return textCodes.split(","); + } ++ return []; + }, + + /** diff --git a/yarn.lock b/yarn.lock index 92fb69c23..ee167eb68 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2678,7 +2678,7 @@ ansi-styles@^3.2.0, ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" -any-promise@^1.0.0, any-promise@^1.3.0: +any-promise@^1.0.0: version "1.3.0" resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" @@ -15093,14 +15093,6 @@ speedometer@~0.1.2: version "0.1.4" resolved "https://registry.yarnpkg.com/speedometer/-/speedometer-0.1.4.tgz#9876dbd2a169d3115402d48e6ea6329c8816a50d" -spellchecker@3.7.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/spellchecker/-/spellchecker-3.7.0.tgz#d63e6fd612352b0108e7bbf942f271665ff63c8b" - integrity sha512-saQT4BR9nivbK70s0YjyIlSbZzO6bfWRULcGL2JU7fi7wotOnWl70P0QoUwwLywNQJQ47osgCo6GmOlqzRTxbQ== - dependencies: - any-promise "^1.3.0" - nan "^2.14.0" - split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" @@ -16162,6 +16154,11 @@ typescript@3.7.4: resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.4.tgz#1743a5ec5fef6a1fa9f3e4708e33c81c73876c19" integrity sha512-A25xv5XCtarLwXpcDNZzCGvW2D1S3/bACratYBx2sax8PefsFhlYmkQicKHvpYflFS8if4zne5zT5kpJ7pzuvw== +typo-js@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/typo-js/-/typo-js-1.1.0.tgz#a5a9f592bcb453666bf70c9694da58705d025ed8" + integrity sha512-W3kLbx+ML9PBl5Bzso/lTvVxk4BCveSNAtQeht59FEtxCdGThmn6wSHA4Xq3eQYAK24NHdisMM4JmsK0GFy/pg== + ua-parser-js@^0.7.18: version "0.7.19" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.19.tgz#94151be4c0a7fb1d001af7022fdaca4642659e4b"