diff --git a/lib/autocomplete-manager.js b/lib/autocomplete-manager.js index 1dd22704..f55fc5a6 100644 --- a/lib/autocomplete-manager.js +++ b/lib/autocomplete-manager.js @@ -43,6 +43,11 @@ class AutocompleteManager { this.displaySuggestions = this.displaySuggestions.bind(this) this.hideSuggestionList = this.hideSuggestionList.bind(this) + this.inlineMode = false; + this.previousPrefix = null; + this.previousReplacement = null; + this.previousSuggestionIndex = -1; + this.showOrHideSuggestionListForBufferChanges = this.showOrHideSuggestionListForBufferChanges.bind(this) this.providerManager = new ProviderManager() this.suggestionList = new SuggestionList() @@ -190,6 +195,7 @@ class AutocompleteManager { this.subscriptions.add(atom.config.observe('autocomplete-plus.enableAutoConfirmSingleSuggestion', (value) => { this.autoConfirmSingleSuggestionEnabled = value })) this.subscriptions.add(atom.config.observe('autocomplete-plus.consumeSuffix', (value) => { this.consumeSuffix = value })) this.subscriptions.add(atom.config.observe('autocomplete-plus.useAlternateScoring', (value) => { this.useAlternateScoring = value })) + this.subscriptions.add(atom.config.observe('autocomplete-plus.inlineMode', (value) => { this.inlineMode = true })) this.subscriptions.add(atom.config.observe('autocomplete-plus.fileBlacklist', (value) => { if (value) { this.fileBlacklist = value.map((s) => { return s.trim() }) @@ -214,6 +220,7 @@ class AutocompleteManager { handleCommands () { return this.subscriptions.add(atom.commands.add('atom-text-editor', { 'autocomplete-plus:activate': (event) => { + if (!this.isValidContext()) return event.abortKeyBinding() this.shouldDisplaySuggestions = true let activatedManually = true if (event.detail && event.detail.activatedManually !== null && typeof event.detail.activatedManually !== 'undefined') { @@ -232,6 +239,15 @@ class AutocompleteManager { })) } + /// Returns true if the last cursor is next to a non-whitespace. + isValidContext() { + const cursor = this.editor.getLastCursor(); + const position = cursor.getBufferPosition(); + if (position.column === 0) return false; + const char = this.editor.getBuffer().getTextInRange([[position.row, position.column-1], position]); + return char.match(this.getWordCharacterRegex()); + } + // Private: Finds suggestions for the current prefix, sets the list items, // positions the overlay and shows it findSuggestions (activatedManually) { @@ -243,7 +259,9 @@ class AutocompleteManager { const bufferPosition = cursor.getBufferPosition() const scopeDescriptor = cursor.getScopeDescriptor() - const prefix = this.getPrefix(this.editor, bufferPosition, scopeDescriptor) // Passed to providers with API version >= 4.0.0 + const prefix = this.inlineMode && this.previousPrefix + || this.getPrefix(this.editor, bufferPosition, scopeDescriptor) // Passed to providers with API version >= 4.0.0 + this.previousPrefix = prefix; const legacyPrefix = this.getLegacyPrefix(this.editor, bufferPosition) // Passed to providers with API version < 4.0.0 return this.getSuggestionsFromProviders({editor: this.editor, bufferPosition, scopeDescriptor, prefix, legacyPrefix, activatedManually}) @@ -351,6 +369,9 @@ class AutocompleteManager { if (options.activatedManually && this.shouldDisplaySuggestions && this.autoConfirmSingleSuggestionEnabled && suggestions.length === 1) { // When there is one suggestion in manual mode, just confirm it return this.confirm(suggestions[0]) + } else if (options.activatedManually && this.inlineMode && suggestions.length >= 1) { + this.previousSuggestionIndex = (this.previousSuggestionIndex + 1) % suggestions.length; + return this.confirm(suggestions[this.previousSuggestionIndex], true) } else { return this.displaySuggestions(suggestions, options) } @@ -528,7 +549,7 @@ See https://github.com/atom/autocomplete-plus/wiki/Provider-API` // Private: Gets called when the user successfully confirms a suggestion // // match - An {Object} representing the confirmed suggestion - confirm (suggestion) { + confirm (suggestion, keepSuggestionList) { if ((this.editor == null) || (suggestion == null) || !!this.disposed) { return } const apiVersion = this.providerManager.apiVersionForProvider(suggestion.provider) @@ -548,7 +569,8 @@ See https://github.com/atom/autocomplete-plus/wiki/Provider-API` } } - this.hideSuggestionList() + // when manually triggered, and in inlineMode, we don't want to reset the suggestions + if (!keepSuggestionList) this.hideSuggestionList() this.replaceTextWithMatch(suggestion) @@ -583,6 +605,10 @@ See https://github.com/atom/autocomplete-plus/wiki/Provider-API` this.suggestionList.changeItems(null) this.suggestionList.hide() this.shouldDisplaySuggestions = false + // reset the inlineMode state + this.previousPrefix = null; + this.previousReplacement = null; + this.previousSuggestionIndex = -1; } requestHideSuggestionList (command) { @@ -613,17 +639,21 @@ See https://github.com/atom/autocomplete-plus/wiki/Provider-API` for (let i = 0; i < cursors.length; i++) { const cursor = cursors[i] const endPosition = cursor.getBufferPosition() - const beginningPosition = [endPosition.row, endPosition.column - suggestion.replacementPrefix.length] + //const beginningPosition = [endPosition.row, endPosition.column - suggestion.replacementPrefix.length] + const prefix = this.inlineMode && this.previousReplacement || suggestion.replacementPrefix; + const beginningPosition = [endPosition.row, endPosition.column - prefix.length] - if (this.editor.getTextInBufferRange([beginningPosition, endPosition]) === suggestion.replacementPrefix) { + if (this.editor.getTextInBufferRange([beginningPosition, endPosition]) === prefix) { const suffix = this.consumeSuffix ? this.getSuffix(this.editor, endPosition, suggestion) : '' if (suffix.length) { cursor.moveRight(suffix.length) } - cursor.selection.selectLeft(suggestion.replacementPrefix.length + suffix.length) + cursor.selection.selectLeft(prefix.length + suffix.length) if ((suggestion.snippet != null) && (this.snippetsManager != null)) { this.snippetsManager.insertSnippet(suggestion.snippet, this.editor, cursor) } else { - cursor.selection.insertText(suggestion.text != null ? suggestion.text : suggestion.snippet, { + const text = suggestion.text != null ? suggestion.text : suggestion.snippet; + this.previousReplacement = text; + cursor.selection.insertText(text, { autoIndentNewline: this.editor.shouldAutoIndent(), autoDecreaseIndent: this.editor.shouldAutoIndent() }) @@ -722,6 +752,11 @@ See https://github.com/atom/autocomplete-plus/wiki/Provider-API` showOrHideSuggestionListForBufferChanges ({changes}) { if (this.disposed) return + if (this.inlineMode && this.previousPrefix + && changes.some(({oldText, newText}) => newText === this.previousReplacement)) { + this.cancelHideSuggestionListRequest() + return + } const lastCursorPosition = this.editor.getLastCursor().getBufferPosition() const changeOccurredNearLastCursor = changes.some(({newRange}) => { @@ -747,7 +782,6 @@ See https://github.com/atom/autocomplete-plus/wiki/Provider-API` } } }) - if (shouldActivate && this.shouldSuppressActivationForEditorClasses()) shouldActivate = false } diff --git a/package.json b/package.json index fe44aa93..e5b28033 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { "name": "autocomplete-plus", - "version": "2.40.4", + "version": "2.40.4+eweitnauer", "main": "./lib/main", "description": "Display possible completions in the editor while typing", - "repository": "https://github.com/atom/autocomplete-plus", + "repository": "https://github.com/eweitnauer/autocomplete-plus", "license": "MIT", "engines": { "atom": ">=0.189.0 <2.0.0" @@ -71,6 +71,13 @@ "minimum": 1, "order": 3 }, + "inlineMode": { + "title": "Inline Mode", + "description": "The activation key will cycle through the suggestions without showing the suggestion list.", + "type": "boolean", + "default": false, + "order": 3.5 + }, "confirmCompletion": { "title": "Keymap For Confirming A Suggestion", "description": "You should use the key(s) indicated here to confirm a suggestion from the suggestion list and have it inserted into the file.",