diff --git a/.editorconfig b/.editorconfig index e98111f..4f4b9b5 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,5 +11,10 @@ max_line_length = 80 tab_width = 2 trim_trailing_whitespace = true -[*.{js,ts,coffee}] +[*.{ts,coffee}] +quote_type = single + +[*.js] +indent_size = 4 +tab_width = 4 quote_type = single diff --git a/lib/corrections-view.js b/lib/corrections-view.js index ba6a134..774c335 100644 --- a/lib/corrections-view.js +++ b/lib/corrections-view.js @@ -44,12 +44,10 @@ export default class CorrectionsView { this.editor.buffer.file && this.editor.buffer.file.path ) { - [ - projectPath, - relativePath, - ] = atom.project.relativizePath( - this.editor.buffer.file.path - ); + [projectPath, relativePath] = + atom.project.relativizePath( + this.editor.buffer.file.path + ); } const args = { id: this.id, projectPath, relativePath }; diff --git a/lib/locale-checker.js b/lib/locale-checker.js index 75c66d4..1de757e 100644 --- a/lib/locale-checker.js +++ b/lib/locale-checker.js @@ -1,6 +1,7 @@ const spellchecker = require('spellchecker'); const pathspec = require('atom-pathspec'); const env = require('./checker-env'); +const createLog = require('./logging'); // The locale checker is a checker that takes a locale string (`en-US`) and // optionally a path and then checks it. @@ -21,12 +22,8 @@ class LocaleChecker { this.enabled = true; this.hasSystemChecker = hasSystemChecker; this.inferredLocale = inferredLocale; - if (atom.config.get('spell-check.enableDebug')) { - debug = require('debug'); - this.log = debug('spell-check:locale-checker').extend(locale); - } else { - this.log = (str) => {}; - } + this.log = createLog().extend('locale-checker').extend(locale); + this.log( 'enabled', this.isEnabled(), diff --git a/lib/logging.js b/lib/logging.js new file mode 100644 index 0000000..229d581 --- /dev/null +++ b/lib/logging.js @@ -0,0 +1,134 @@ +// To avoid increasing the startup time and not loading modules that aren't +// required, we use a thin wrapper around the `debug` logging library that +// allows us to configure it via the Atom settings. + +let enabled = atom.config.get('spell-check.enableDebug'); +let loggers = {}; + +function updateLocalStorage() { + // If we aren't enabled, we do nothing. + if (!enabled) { + return; + } + + // `debug` requires `localStorage.debug` to contain the prefix for keys. + // Because we have a configuration, we make sure they are there to avoid + // a second step to enabling logging. We only check for the presence of + // *any* spell-check reference so the user can customize it without worrying + // about it being overridden. + if (localStorage.debug === undefined) { + localStorage.debug = ''; + } + + if (localStorage.debug.indexOf('spell-check') < 0) { + let keys = localStorage.debug.split(',').filter((x) => x !== ''); + keys.push('spell-check'); + keys.push('spell-check:*'); + localStorage.debug = keys.join(','); + } +} + +/** + * Updates the registered loggers along with the new one to use `debug` instead + * of the internal, null sink. + */ +function update() { + // If we aren't enabled, then don't do anything. + enabled = atom.config.get('spell-check.enableDebug'); + + // Go through all the existing loggers and rebind or set them up using the + // new settings. + for (const scope in loggers) { + if (loggers.hasOwnProperty(scope)) { + // Pull out the current logger and make sure it is properly enabled. + let config = loggers[scope]; + + config.wrapper.enabled = enabled; + + // If we are enabled, then load `debug` and use that to create a + // proper log sink using that package. + if (enabled) { + const debug = require('debug'); + + config.sink = debug(scope); + config.sink.log = console.log.bind(console); + } + } + } + + // Make sure the local storage keys. + updateLocalStorage(); +} + +/** + * Creates a logger based on the atom settings. If the user has enabled logging + * for spell-check, then this also ensures that the spell-check entries will be + * added to localStorage for debugging. + * + * @param {string} scope The name of the scope, such as "spell-check" or + "spell-check:locale-checker:en-US". + * @returns A lambda that is either does nothing or it is the full debug call. + */ +function create(scope) { + // See if we already have a logger defined for this value. + if (loggers[scope] !== undefined) { + return loggers[scope].wrapper; + } + + // We use a logger object to contain all the variables and components of + // a log at each level. We do this so we can turn logging on or after based + // on editor settings. + let config = { + scope: scope, + sink: undefined, + }; + + // If we are enabled, then we've already loaded the `debug` module. + if (enabled) { + const debug = require('debug'); + config.sink = debug(scope); + config.sink.log = console.log.bind(console); + } + + // Create the function that will actually perform the logging. This function + // uses the `arguments` property to pass values into the inner logger. + config.wrapper = function () { + if (config.sink !== undefined) { + config.sink.apply(config.sink, arguments); + } + }; + + /** + * The `extend` method is used to create a new logger with a ":" between the + * old scope and the new one. + * + * @param {string} newScope The name of the inner scope to extend. + * @returns The logging function. + */ + config.extend = function (newScope) { + return create([scope, newScope].join(':')); + }; + + // Wrap everything into the wrapper so it acts like `debug`. + config.wrapper.config = config; + config.wrapper.extend = config.extend; + config.wrapper.update = update; + config.wrapper.enabled = enabled; + + // Cache the loggers for updating later and return it. + loggers[scope] = config; + + return config.wrapper; +} + +/** + * Creates the root logger. + */ +function createRoot() { + return create('spell-check'); +} + +// Set up the first-time calls. +updateLocalStorage(); + +module.exports = createRoot; diff --git a/lib/main.js b/lib/main.js index df66c98..3e0c528 100644 --- a/lib/main.js +++ b/lib/main.js @@ -1,4 +1,5 @@ const { CompositeDisposable } = require('atom'); +const createLog = require('./logging'); let SpellCheckView = null; let spellCheckViews = {}; @@ -9,11 +10,7 @@ let log = (str) => {}; module.exports = { activate() { - if (atom.config.get('spell-check.enableDebug')) { - debug = require('debug'); - log = debug('spell-check'); - } - + log = createLog(); log('initializing'); this.subs = new CompositeDisposable(); @@ -115,6 +112,11 @@ module.exports = { } ) ); + this.subs.add( + atom.config.onDidChange('spell-check.enableDebug', (_) => { + log.update(); + }) + ); // Hook up the UI and processing. this.subs.add( diff --git a/lib/spell-check-manager.js b/lib/spell-check-manager.js index 2c50c3e..d44cd65 100644 --- a/lib/spell-check-manager.js +++ b/lib/spell-check-manager.js @@ -1,4 +1,5 @@ const env = require('./checker-env'); +const createLog = require('./logging'); class SpellCheckerManager { static initClass() { @@ -316,6 +317,15 @@ class SpellCheckerManager { continue; } + // Do a little sanity checking. + if (!checker.suggest) { + this.log( + 'spell checker does not have a .suggest function', + checker + ); + continue; + } + // Get the suggestions for this word. index = 0; priority = checker.getPriority(); @@ -423,12 +433,7 @@ class SpellCheckerManager { init() { // Set up logging. - if (atom.config.get('spell-check.enableDebug')) { - debug = require('debug'); - this.log = debug('spell-check:spell-check-manager'); - } else { - this.log = (str) => {}; - } + this.log = createLog().extend('spell-check-manager'); // Set up the system checker. const hasSystemChecker = this.useSystem && env.isSystemSupported(); diff --git a/lib/spell-check-view.js b/lib/spell-check-view.js index c6545bf..b4d6e92 100644 --- a/lib/spell-check-view.js +++ b/lib/spell-check-view.js @@ -24,7 +24,8 @@ module.exports = SpellCheckView = class SpellCheckView { let marker; if ( (marker = this.markerLayer.findMarkers({ - containsBufferPosition: this.editor.getCursorBufferPosition(), + containsBufferPosition: + this.editor.getCursorBufferPosition(), })[0]) ) { if (CorrectionsView == null) { @@ -202,9 +203,8 @@ module.exports = SpellCheckView = class SpellCheckView { const currentScreenPosition = atom.views .getView(this.editor) .component.screenPositionForMouseEvent(mouseEvent); - const currentBufferPosition = this.editor.bufferPositionForScreenPosition( - currentScreenPosition - ); + const currentBufferPosition = + this.editor.bufferPositionForScreenPosition(currentScreenPosition); // Check to see if the selected word is incorrect. if ( diff --git a/lib/system-checker.js b/lib/system-checker.js index fa4dbc3..65ba47c 100644 --- a/lib/system-checker.js +++ b/lib/system-checker.js @@ -2,6 +2,7 @@ let instance; const spellchecker = require('spellchecker'); const pathspec = require('atom-pathspec'); const env = require('./checker-env'); +const createLog = require('./logging'); // Initialize the global spell checker which can take some time. We also force // the use of the system or operating system library instead of Hunspell. @@ -23,12 +24,7 @@ if (env.isSystemSupported()) { // due to some memory bug. class SystemChecker { constructor() { - if (atom.config.get('spell-check.enableDebug')) { - debug = require('debug'); - this.log = debug('spell-check:system-checker'); - } else { - this.log = (str) => {}; - } + this.log = createLog().extend('system-checker'); this.log('enabled', this.isEnabled(), this.getStatus()); } diff --git a/spec/spell-check-spec.js b/spec/spell-check-spec.js index 103992e..95653dd 100644 --- a/spec/spell-check-spec.js +++ b/spec/spell-check-spec.js @@ -241,9 +241,8 @@ describe('Spell check', function () { editorElement, 'spell-check:correct-misspelling' ); - correctionsElement = editorElement.querySelector( - '.corrections' - ); + correctionsElement = + editorElement.querySelector('.corrections'); expect(correctionsElement).toBeDefined(); expect( correctionsElement.querySelectorAll('li').length