diff --git a/browser/src/Services/Completion/CompletionSelectors.ts b/browser/src/Services/Completion/CompletionSelectors.ts index 127c46efcc..0d933e52bf 100644 --- a/browser/src/Services/Completion/CompletionSelectors.ts +++ b/browser/src/Services/Completion/CompletionSelectors.ts @@ -4,6 +4,7 @@ * Selectors are functions that take a state and derive a value from it. */ +import { configuration } from "./../Configuration" import { ICompletionState } from "./CompletionState" import * as types from "vscode-languageserver-types" @@ -12,6 +13,31 @@ const EmptyCompletions: types.CompletionItem[] = [] import * as CompletionUtility from "./CompletionUtility" +export const shouldFilterBeCaseSensitive = (searchString: string): boolean => { + // TODO: Technically, this makes the reducer 'impure', + // which is not ideal - need to refactor eventually. + // + // One option is to plumb through the configuration setting + // from the top-level, but it might be worth extracting + // out the filter strategy in general. + const caseSensitivitySetting = configuration.getValue("editor.completions.caseSensitive") + + if (caseSensitivitySetting === false) { + return false + } else if (caseSensitivitySetting === true) { + return true + } else { + // "Smart" casing strategy + // If the string is all lower-case, not case sensitive.. + if (searchString === searchString.toLowerCase()) { + return false + // Otherwise, it is case sensitive.. + } else { + return true + } + } +} + export const getFilteredCompletions = (state: ICompletionState): types.CompletionItem[] => { if (!state.completionResults.completions || !state.completionResults.completions.length) { return EmptyCompletions @@ -72,12 +98,13 @@ export const filterCompletionOptions = ( return null } - const filterRegEx = new RegExp("^" + searchText.split("").join(".*") + ".*") + const isCaseSensitive = shouldFilterBeCaseSensitive(searchText) - const filteredOptions = items.filter(f => { - const textToFilterOn = f.filterText || f.label - return textToFilterOn.match(filterRegEx) - }) + if (!isCaseSensitive) { + searchText = searchText.toLocaleLowerCase() + } + + const filteredOptions = processSearchText(searchText, items, isCaseSensitive) return filteredOptions.sort((itemA, itemB) => { const itemAFilterText = itemA.filterText || itemA.label @@ -89,3 +116,21 @@ export const filterCompletionOptions = ( return indexOfB - indexOfA }) } + +export const processSearchText = ( + searchText: string, + items: types.CompletionItem[], + isCaseSensitive: boolean, +): types.CompletionItem[] => { + const filterRegExp = new RegExp(".*" + searchText.split("").join(".*") + ".*") + + return items.filter(f => { + let textToFilterOn = f.filterText || f.label + + if (!isCaseSensitive) { + textToFilterOn = textToFilterOn.toLowerCase() + } + + return textToFilterOn.match(filterRegExp) + }) +} diff --git a/browser/src/Services/Configuration/DefaultConfiguration.ts b/browser/src/Services/Configuration/DefaultConfiguration.ts index 79bdae8a29..6253baf6ac 100644 --- a/browser/src/Services/Configuration/DefaultConfiguration.ts +++ b/browser/src/Services/Configuration/DefaultConfiguration.ts @@ -99,6 +99,7 @@ const BaseConfiguration: IConfigurationValues = { "editor.quickInfo.delay": 500, "editor.completions.mode": "oni", + "editor.completions.caseSensitive": true, "editor.errors.slideOnFocus": true, "editor.formatting.formatOnSwitchToNormalMode": false, @@ -459,7 +460,9 @@ const LinuxConfigOverrides: Partial = { const PlatformConfigOverride = Platform.isWindows() ? WindowsConfigOverrides - : Platform.isLinux() ? LinuxConfigOverrides : MacConfigOverrides + : Platform.isLinux() + ? LinuxConfigOverrides + : MacConfigOverrides export const DefaultConfiguration = { ...BaseConfiguration, diff --git a/browser/src/Services/Configuration/IConfigurationValues.ts b/browser/src/Services/Configuration/IConfigurationValues.ts index 60eb8ad501..a52f9bfa62 100644 --- a/browser/src/Services/Configuration/IConfigurationValues.ts +++ b/browser/src/Services/Configuration/IConfigurationValues.ts @@ -150,6 +150,9 @@ export interface IConfigurationValues { // a custom init.vim, as that may cause problematic behavior "editor.completions.mode": string + // Decide whether or not the completion matching should be case sensitive + "editor.completions.caseSensitive": boolean | string + // If true (default), ligatures are enabled "editor.fontLigatures": boolean "editor.fontSize": string