json.ts 6.9 KB
Newer Older
E
Erich Gamma 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
'use strict';

import EditorCommon = require('vs/editor/common/editorCommon');
import Modes = require('vs/editor/common/modes');
import Network = require('vs/base/common/network');
import WinJS = require('vs/base/common/winjs.base');
import supports = require('vs/editor/common/modes/supports');
import Platform = require('vs/platform/platform');
import nls = require('vs/nls');
import jsonWorker = require('vs/languages/json/common/jsonWorker');
import jsonSchema = require('vs/base/common/jsonSchema');
import tokenization = require('vs/languages/json/common/features/tokenization');
import jsonSchemaService = require('vs/languages/json/common/jsonSchemaService');
import {AbstractMode, createWordRegExp} from 'vs/editor/common/modes/abstractMode';
import {OneWorkerAttr, AllWorkersAttr} from 'vs/platform/thread/common/threadService';
import {IThreadService, IThreadSynchronizableObject} from 'vs/platform/thread/common/thread';
import {AsyncDescriptor2, createAsyncDescriptor2} from 'vs/platform/instantiation/common/descriptors';
import {OnEnterSupport} from 'vs/editor/common/modes/supports/onEnter';
import {IJSONContributionRegistry, Extensions, ISchemaContributions} from 'vs/languages/json/common/jsonContributionRegistry';
import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation';

export class JSONMode extends AbstractMode<jsonWorker.JSONWorker> implements Modes.IExtraInfoSupport, Modes.IOutlineSupport, IThreadSynchronizableObject<ISchemaContributions> {

	public tokenizationSupport: Modes.ITokenizationSupport;
	public electricCharacterSupport: Modes.IElectricCharacterSupport;
	public characterPairSupport: Modes.ICharacterPairSupport;

	public extraInfoSupport: Modes.IExtraInfoSupport;
	public outlineSupport: Modes.IOutlineSupport;
	public formattingSupport: Modes.IFormattingSupport;

	public suggestSupport: Modes.ISuggestSupport;

	public outlineGroupLabel : { [name: string]: string; };

	public onEnterSupport: Modes.IOnEnterSupport;

	constructor(
		descriptor:Modes.IModeDescriptor,
		@IInstantiationService instantiationService: IInstantiationService,
		@IThreadService threadService: IThreadService
	) {
		super(descriptor, instantiationService, threadService);

		this.tokenizationSupport = tokenization.createTokenizationSupport(this, true);
		this.electricCharacterSupport = new supports.BracketElectricCharacterSupport(this, { brackets: [
			{ tokenType:'delimiter.bracket.json', open: '{', close: '}', isElectric: true },
			{ tokenType:'delimiter.array.json', open: '[', close: ']', isElectric: true }
		] });

		this.extraInfoSupport = this;

		// Initialize Outline support
		this.outlineSupport = this;
		this.outlineGroupLabel = Object.create(null);
		this.outlineGroupLabel['object'] = nls.localize('object', "objects");
		this.outlineGroupLabel['array'] = nls.localize('array', "arrays");
		this.outlineGroupLabel['string'] = nls.localize('string', "strings");
		this.outlineGroupLabel['number'] = nls.localize('number', "numbers");
		this.outlineGroupLabel['boolean'] = nls.localize('boolean', "booleans");
		this.outlineGroupLabel['null'] = nls.localize('undefined', "undefined");

		this.formattingSupport = this;

		this.characterPairSupport = new supports.CharacterPairSupport(this, {
			autoClosingPairs:
				[	{ open: '{', close: '}', notIn: ['string'] },
					{ open: '[', close: ']', notIn: ['string'] },
					{ open: '"', close: '"', notIn: ['string'] }
				]});

		this.suggestSupport = new supports.SuggestSupport(this, {
			triggerCharacters: [],
			excludeTokens: ['comment.line.json', 'comment.block.json'],
			suggest: (resource, position) => this.suggest(resource, position)});

		this.onEnterSupport = new OnEnterSupport(this.getId(), {
			brackets: [
				{ open: '{', close: '}' },
				{ open: '[', close: ']' }
			]
		});
	}

	public creationDone(): void {
		super.creationDone();
		if (this._threadService.isInMainThread) {
			// Configure all workers
			this._configureWorkerSchemas(this.getSchemaConfiguration());
			var contributionRegistry = <IJSONContributionRegistry> Platform.Registry.as(Extensions.JSONContribution);
			contributionRegistry.addRegistryChangedListener(e => {
				this._configureWorkerSchemas(this.getSchemaConfiguration());
			});
		}
	}

	private getSchemaConfiguration() : ISchemaContributions {
		var contributionRegistry = <IJSONContributionRegistry> Platform.Registry.as(Extensions.JSONContribution);
		return contributionRegistry.getSchemaContributions();
	}

	public getSerializableState(): ISchemaContributions {
		return this.getSchemaConfiguration();
	}

	public setData(data:ISchemaContributions): void {
		// It is ok to not join the promise. Workers are managed using a special
		// worker promise and the next call to the worker will wait until this
		// call went through.
		this._worker((w) => w.setSchemaContributions(data));
	}

	protected _getWorkerDescriptor(): AsyncDescriptor2<Modes.IMode, Modes.IWorkerParticipant[], jsonWorker.JSONWorker> {
		return createAsyncDescriptor2('vs/languages/json/common/jsonWorker', 'JSONWorker');
	}

	static $_configureWorkerSchemas = AllWorkersAttr(JSONMode, JSONMode.prototype._configureWorkerSchemas);
	private _configureWorkerSchemas(data:ISchemaContributions): WinJS.TPromise<boolean> {
		return this._worker((w) => w.setSchemaContributions(data));
	}

	static $computeInfo = OneWorkerAttr(JSONMode, JSONMode.prototype.computeInfo);
	public computeInfo(resource:Network.URL, position:EditorCommon.IPosition): WinJS.TPromise<Modes.IComputeExtraInfoResult> {
		return this._worker((w) => w.computeInfo(resource, position));
	}

	static $getOutline = OneWorkerAttr(JSONMode, JSONMode.prototype.getOutline);
	public getOutline(resource:Network.URL):WinJS.TPromise<Modes.IOutlineEntry[]> {
		return this._worker((w) => w.getOutline(resource));
	}

	static $formatDocument = OneWorkerAttr(JSONMode, JSONMode.prototype.formatDocument);
	public formatDocument(resource:Network.URL, options:Modes.IFormattingOptions):WinJS.TPromise<EditorCommon.ISingleEditOperation[]> {
		return this._worker((w) => w.format(resource, null, options));
	}

	static $formatRange = OneWorkerAttr(JSONMode, JSONMode.prototype.formatRange);
	public formatRange(resource:Network.URL, range:EditorCommon.IRange, options:Modes.IFormattingOptions):WinJS.TPromise<EditorCommon.ISingleEditOperation[]> {
		return this._worker((w) => w.format(resource, range, options));
	}

	public getCommentsConfiguration():Modes.ICommentsConfiguration {
		return {
			lineCommentTokens: ['//'],
			blockCommentStartToken: '/*',
			blockCommentEndToken: '*/'
		};
	}

	private static WORD_DEFINITION = createWordRegExp('.-');
	public getWordDefinition():RegExp {
		return JSONMode.WORD_DEFINITION;
	}
}