diff --git a/README.md b/README.md index cbda943..c7e2888 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ inshellisense supports the following shells: ## Configuration -All configuration is done through a [toml](https://toml.io/) file located at `~/.inshellisenserc`. The [JSON schema](https://json-schema.org/) for the configuration file can be found [here](https://github.com/microsoft/inshellisense/blob/main/src/utils/config.ts). +All configuration is done through a [toml](https://toml.io/) file. You can create this file at `~/.inshellisenserc` or, for XDG compliance, at `~/.config/inshellisense/rc.toml`. The [JSON schema](https://json-schema.org/) for the configuration file can be found [here](https://github.com/microsoft/inshellisense/blob/main/src/utils/config.ts). ### Keybindings diff --git a/src/utils/config.ts b/src/utils/config.ts index b2f3143..f6097f6 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -108,9 +108,13 @@ const configSchema = { additionalProperties: false, }; -const configFile = ".inshellisenserc"; +const rcFile = ".inshellisenserc"; +const xdgFile = "rc.toml"; const cachePath = path.join(os.homedir(), ".inshellisense"); -const configPath = path.join(os.homedir(), configFile); +const rcPath = path.join(os.homedir(), rcFile); +const xdgPath = path.join(os.homedir(), ".config", "inshellisense", xdgFile); + +const configPaths = [rcPath, xdgPath]; let globalConfig: Config = { bindings: { @@ -123,37 +127,40 @@ let globalConfig: Config = { export const getConfig = (): Config => globalConfig; export const loadConfig = async (program: Command) => { - if (fs.existsSync(configPath)) { - let config: Config; - try { - config = toml.parse((await fsAsync.readFile(configPath)).toString()); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } catch (e: any) { - program.error(`${configFile} is invalid toml. Parsing error on line ${e.line}, column ${e.column}: ${e.message}`); - } - const isValid = ajv.validate(configSchema, config); - if (!isValid) { - program.error(`${configFile} is invalid: ${ajv.errorsText()}`); + configPaths.forEach(async (configPath) => { + if (fs.existsSync(configPath)) { + let config: Config; + try { + config = toml.parse((await fsAsync.readFile(configPath)).toString()); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } catch (e: any) { + program.error(`${configPath} is invalid toml. Parsing error on line ${e.line}, column ${e.column}: ${e.message}`); + } + const isValid = ajv.validate(configSchema, config); + if (!isValid) { + program.error(`${configPath} is invalid: ${ajv.errorsText()}`); + } + globalConfig = { + bindings: { + nextSuggestion: config?.bindings?.nextSuggestion ?? globalConfig.bindings.nextSuggestion, + previousSuggestion: config?.bindings?.previousSuggestion ?? globalConfig.bindings.previousSuggestion, + acceptSuggestion: config?.bindings?.acceptSuggestion ?? globalConfig.bindings.acceptSuggestion, + dismissSuggestions: config?.bindings?.dismissSuggestions ?? globalConfig.bindings.dismissSuggestions, + }, + prompt: { + bash: config.prompt?.bash ?? globalConfig?.prompt?.bash, + powershell: config.prompt?.powershell ?? globalConfig?.prompt?.powershell, + xonsh: config.prompt?.xonsh ?? globalConfig?.prompt?.xonsh, + pwsh: config.prompt?.pwsh ?? globalConfig?.prompt?.pwsh, + nu: config.prompt?.nu ?? globalConfig?.prompt?.nu, + }, + specs: { + path: [...(config?.specs?.path ?? []), ...(config?.specs?.path ?? [])], + }, + }; } - globalConfig = { - bindings: { - nextSuggestion: config?.bindings?.nextSuggestion ?? globalConfig.bindings.nextSuggestion, - previousSuggestion: config?.bindings?.previousSuggestion ?? globalConfig.bindings.previousSuggestion, - acceptSuggestion: config?.bindings?.acceptSuggestion ?? globalConfig.bindings.acceptSuggestion, - dismissSuggestions: config?.bindings?.dismissSuggestions ?? globalConfig.bindings.dismissSuggestions, - }, - prompt: { - bash: config.prompt?.bash, - powershell: config.prompt?.powershell, - xonsh: config.prompt?.xonsh, - pwsh: config.prompt?.pwsh, - nu: config.prompt?.nu, - }, - specs: { - path: [`${os.homedir()}/.fig/autocomplete/build`, ...(config?.specs?.path ?? [])], - }, - }; - } + }); + globalConfig.specs = { path: [`${os.homedir()}/.fig/autocomplete/build`, ...(globalConfig.specs?.path ?? [])] }; }; export const deleteCacheFolder = async (): Promise => {