diff --git a/packages/debug/src/browser/preferences/launch-preferences.spec.ts b/packages/debug/src/browser/preferences/launch-preferences.spec.ts index 86e82821f52e9..aef85e3b980c1 100644 --- a/packages/debug/src/browser/preferences/launch-preferences.spec.ts +++ b/packages/debug/src/browser/preferences/launch-preferences.spec.ts @@ -46,6 +46,9 @@ import { bindUserStorage } from '@theia/userstorage/lib/browser/user-storage-fro import { FileSystemWatcherServer } from '@theia/filesystem/lib/common/filesystem-watcher-protocol'; import { MockFilesystemWatcherServer } from '@theia/filesystem/lib/common/test/mock-filesystem-watcher-server'; import { bindLaunchPreferences } from './launch-preferences'; +import { EditorManager } from '@theia/editor/lib/browser/editor-manager'; +import URI from '@theia/core/lib/common/uri'; +import { EditorWidget } from '@theia/editor/lib/browser/editor-widget'; disableJSDOM(); @@ -333,12 +336,12 @@ describe('Launch Preferences', () => { function testLaunchAndSettingsSuite({ name, expectation, launch, only, configMode }: { - name: string, - expectation: any, - launch?: any, - only?: boolean, - configMode?: ConfigMode - }): void { + name: string, + expectation: any, + launch?: any, + only?: boolean, + configMode?: ConfigMode + }): void { testSuite({ name: name + ' Launch Configuration', launch, @@ -398,13 +401,13 @@ describe('Launch Preferences', () => { function testConfigSuite({ configMode, expectation, inspectExpectation, settings, launch, only }: { - configMode: ConfigMode - expectation: any, - inspectExpectation?: any, - launch?: any, - settings?: any, - only?: boolean - }): void { + configMode: ConfigMode + expectation: any, + inspectExpectation?: any, + launch?: any, + settings?: any, + only?: boolean + }): void { describe(JSON.stringify(configMode, undefined, 2), () => { @@ -458,6 +461,11 @@ describe('Launch Preferences', () => { bindPreferenceProviders(bind, unbind); bindWorkspacePreferences(bind); container.bind(WorkspaceService).toSelf().inSingletonScope(); + container.bind(EditorManager).toConstantValue({ + getByUri(uri: URI): Promise { + return Promise.resolve(undefined); + } + }); container.bind(WindowService).toConstantValue(new MockWindowService()); const workspaceServer = new MockWorkspaceServer(); diff --git a/packages/preferences/src/browser/abstract-resource-preference-provider.ts b/packages/preferences/src/browser/abstract-resource-preference-provider.ts index d73c5ea13dc79..2fb665c2984ef 100644 --- a/packages/preferences/src/browser/abstract-resource-preference-provider.ts +++ b/packages/preferences/src/browser/abstract-resource-preference-provider.ts @@ -23,6 +23,7 @@ import { MessageService, Resource, ResourceProvider, Disposable } from '@theia/c import { PreferenceProvider, PreferenceSchemaProvider, PreferenceScope, PreferenceProviderDataChange } from '@theia/core/lib/browser'; import URI from '@theia/core/lib/common/uri'; import { PreferenceConfigurations } from '@theia/core/lib/browser/preferences/preference-configurations'; +import { EditorManager, TextEditorDocument } from '@theia/editor/lib/browser'; @injectable() export abstract class AbstractResourcePreferenceProvider extends PreferenceProvider { @@ -30,6 +31,7 @@ export abstract class AbstractResourcePreferenceProvider extends PreferenceProvi protected preferences: { [key: string]: any } = {}; protected resource: Promise; + @inject(EditorManager) protected readonly editorManager: EditorManager; @inject(ResourceProvider) protected readonly resourceProvider: ResourceProvider; @inject(MessageService) protected readonly messageService: MessageService; @inject(PreferenceSchemaProvider) protected readonly schemaProvider: PreferenceSchemaProvider; @@ -102,9 +104,15 @@ export abstract class AbstractResourcePreferenceProvider extends PreferenceProvi return true; } try { + const editor = await this.editorManager.getByUri(new URI(resourceUri!)); + let tabSize: number = 0; + let insertSpaces: boolean = true; + if (editor) { + [tabSize, insertSpaces] = this.detectIndentation(editor.editor.document); + } let newContent = ''; if (path.length || value !== undefined) { - const formattingOptions = { tabSize: 3, insertSpaces: true, eol: '' }; + const formattingOptions = { tabSize, insertSpaces, eol: '' }; const edits = jsoncparser.modify(content, path, value, { formattingOptions }); newContent = jsoncparser.applyEdits(content, edits); } @@ -221,4 +229,33 @@ export abstract class AbstractResourcePreferenceProvider extends PreferenceProvi } } + /** + * Detect the minimum indentation and type of indentation to be used + * as formatting options when using `jsoncparser`. + * @param text the preference text editor document. + * + * @returns a tuple representing the indentation size, and if it spaces. + */ + protected detectIndentation(text: TextEditorDocument): [number, boolean] { + // Get the number of lines present in the text document. + const lineCount = text.lineCount; + // Store the current index which will be used iterate over the document. + let index = 0; + // Iterate over the each line in the text document, getting the first indentation that is not zero. + while (index < lineCount) { + // Get the line content of the document a the given index. + const line = text.getLineContent(index + 1); + // Determine how many leading spaces are present in the document. + const indentation = line.search(/\S|$/); + // Return the first non-zero indentation. + if (indentation > 0) { + // Determine if the line is indented with spaces or tabs. + const isSpaces = !line.startsWith('\t'); + return [indentation, isSpaces]; + } + index++; + } + return [0, true]; + } + }