提交 230b27e8 编写于 作者: B Benjamin Pasero

first version of a new setting to associate file patterns to languages

上级 95e012b1
/*---------------------------------------------------------------------------------------------
* 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 {MarkedString, CompletionItemKind, CompletionItem} from 'vscode-languageserver';
import Strings = require('../utils/strings');
import {IJSONWorkerContribution, ISuggestionsCollector} from '../jsonContributions';
import {JSONLocation} from '../jsonLocation';
import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
let globProperties: CompletionItem[] = [
{ kind: CompletionItemKind.Value, label: localize('assocLabel', "Files with Extension"), insertText: '"*.{{extension}}": "{{language}}"', documentation: localize('assocDescription', "Map all files matching the given pattern to the language with the given id.") },
];
let globValues: CompletionItem[] = [
{ kind: CompletionItemKind.Value, label: localize('languageId', "Language Identifier"), insertText: '"{{language}}"', documentation: localize('languageDescription', "The identifier of the language to associate with the file name pattern.") },
];
export class FileAssociationContribution implements IJSONWorkerContribution {
constructor() {
}
private isSettingsFile(resource: string): boolean {
return Strings.endsWith(resource, '/settings.json');
}
public collectDefaultSuggestions(resource: string, result: ISuggestionsCollector): Thenable<any> {
return null;
}
public collectPropertySuggestions(resource: string, location: JSONLocation, currentWord: string, addValue: boolean, isLast: boolean, result: ISuggestionsCollector): Thenable<any> {
if (this.isSettingsFile(resource) && location.matches(['files.association'])) {
globProperties.forEach((e) => result.add(e));
}
return null;
}
public collectValueSuggestions(resource: string, location: JSONLocation, currentKey: string, result: ISuggestionsCollector): Thenable<any> {
if (this.isSettingsFile(resource) && location.matches(['files.association'])) {
globValues.forEach((e) => result.add(e));
}
return null;
}
public getInfoContribution(resource: string, location: JSONLocation): Thenable<MarkedString[]> {
return null;
}
}
\ No newline at end of file
......@@ -12,19 +12,19 @@ import {JSONLocation} from '../jsonLocation';
import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
let globProperties:CompletionItem[] = [
{ kind: CompletionItemKind.Value, label: localize('fileLabel', "Files by Extension"), insertText: '"**/*.{{extension}}": true', documentation: localize('fileDescription', "Match all files of a specific file extension.")},
{ kind: CompletionItemKind.Value, label: localize('filesLabel', "Files with Multiple Extensions"), insertText: '"**/*.{ext1,ext2,ext3}": true', documentation: localize('filesDescription', "Match all files with any of the file extensions.")},
{ kind: CompletionItemKind.Value, label: localize('derivedLabel', "Files with Siblings by Name"), insertText: '"**/*.{{source-extension}}": { "when": "$(basename).{{target-extension}}" }', documentation: localize('derivedDescription', "Match files that have siblings with the same name but a different extension.")},
{ kind: CompletionItemKind.Value, label: localize('topFolderLabel', "Folder by Name (Top Level)"), insertText: '"{{name}}": true', documentation: localize('topFolderDescription', "Match a top level folder with a specific name.")},
{ kind: CompletionItemKind.Value, label: localize('topFoldersLabel', "Folders with Multiple Names (Top Level)"), insertText: '"{folder1,folder2,folder3}": true', documentation: localize('topFoldersDescription', "Match multiple top level folders.")},
{ kind: CompletionItemKind.Value, label: localize('folderLabel', "Folder by Name (Any Location)"), insertText: '"**/{{name}}": true', documentation: localize('folderDescription', "Match a folder with a specific name in any location.")},
let globProperties: CompletionItem[] = [
{ kind: CompletionItemKind.Value, label: localize('fileLabel', "Files by Extension"), insertText: '"**/*.{{extension}}": true', documentation: localize('fileDescription', "Match all files of a specific file extension.") },
{ kind: CompletionItemKind.Value, label: localize('filesLabel', "Files with Multiple Extensions"), insertText: '"**/*.{ext1,ext2,ext3}": true', documentation: localize('filesDescription', "Match all files with any of the file extensions.") },
{ kind: CompletionItemKind.Value, label: localize('derivedLabel', "Files with Siblings by Name"), insertText: '"**/*.{{source-extension}}": { "when": "$(basename).{{target-extension}}" }', documentation: localize('derivedDescription', "Match files that have siblings with the same name but a different extension.") },
{ kind: CompletionItemKind.Value, label: localize('topFolderLabel', "Folder by Name (Top Level)"), insertText: '"{{name}}": true', documentation: localize('topFolderDescription', "Match a top level folder with a specific name.") },
{ kind: CompletionItemKind.Value, label: localize('topFoldersLabel', "Folders with Multiple Names (Top Level)"), insertText: '"{folder1,folder2,folder3}": true', documentation: localize('topFoldersDescription', "Match multiple top level folders.") },
{ kind: CompletionItemKind.Value, label: localize('folderLabel', "Folder by Name (Any Location)"), insertText: '"**/{{name}}": true', documentation: localize('folderDescription', "Match a folder with a specific name in any location.") },
];
let globValues:CompletionItem[] = [
{ kind: CompletionItemKind.Value, label: localize('trueLabel', "True"), insertText: 'true', documentation: localize('trueDescription', "Enable the pattern.")},
{ kind: CompletionItemKind.Value, label: localize('falseLabel', "False"), insertText: 'false', documentation: localize('falseDescription', "Disable the pattern.")},
{ kind: CompletionItemKind.Value, label: localize('derivedLabel', "Files with Siblings by Name"), insertText: '{ "when": "$(basename).{{extension}}" }', documentation: localize('siblingsDescription', "Match files that have siblings with the same name but a different extension.")}
let globValues: CompletionItem[] = [
{ kind: CompletionItemKind.Value, label: localize('trueLabel', "True"), insertText: 'true', documentation: localize('trueDescription', "Enable the pattern.") },
{ kind: CompletionItemKind.Value, label: localize('falseLabel', "False"), insertText: 'false', documentation: localize('falseDescription', "Disable the pattern.") },
{ kind: CompletionItemKind.Value, label: localize('derivedLabel', "Files with Siblings by Name"), insertText: '{ "when": "$(basename).{{extension}}" }', documentation: localize('siblingsDescription', "Match files that have siblings with the same name but a different extension.") }
];
export class GlobPatternContribution implements IJSONWorkerContribution {
......@@ -40,9 +40,8 @@ export class GlobPatternContribution implements IJSONWorkerContribution {
return null;
}
public collectPropertySuggestions(resource: string, location: JSONLocation, currentWord: string, addValue: boolean, isLast:boolean, result: ISuggestionsCollector) : Thenable<any> {
public collectPropertySuggestions(resource: string, location: JSONLocation, currentWord: string, addValue: boolean, isLast: boolean, result: ISuggestionsCollector): Thenable<any> {
if (this.isSettingsFile(resource) && (location.matches(['files.exclude']) || location.matches(['search.exclude']))) {
globProperties.forEach((e) => result.add(e));
}
......@@ -51,7 +50,6 @@ export class GlobPatternContribution implements IJSONWorkerContribution {
public collectValueSuggestions(resource: string, location: JSONLocation, currentKey: string, result: ISuggestionsCollector): Thenable<any> {
if (this.isSettingsFile(resource) && (location.matches(['files.exclude']) || location.matches(['search.exclude']))) {
globValues.forEach((e) => result.add(e));
}
......
......@@ -30,6 +30,7 @@ import {BowerJSONContribution} from './jsoncontributions/bowerJSONContribution';
import {PackageJSONContribution} from './jsoncontributions/packageJSONContribution';
import {ProjectJSONContribution} from './jsoncontributions/projectJSONContribution';
import {GlobPatternContribution} from './jsoncontributions/globPatternContribution';
import {FileAssociationContribution} from './jsoncontributions/fileAssociationContribution';
import * as nls from 'vscode-nls';
nls.config(process.env['VSCODE_NLS_CONFIG']);
......@@ -118,7 +119,8 @@ let contributions = [
new ProjectJSONContribution(request),
new PackageJSONContribution(request),
new BowerJSONContribution(request),
new GlobPatternContribution()
new GlobPatternContribution(),
new FileAssociationContribution()
];
let jsonSchemaService = new JSONSchemaService(request, workspaceContext, telemetry);
......
......@@ -425,6 +425,7 @@ export const AutoSaveConfiguration = {
export interface IFilesConfiguration {
files: {
association: { [filePattern: string]: string };
exclude: glob.IExpression;
encoding: string;
trimTrailingWhitespace: boolean;
......
......@@ -26,6 +26,7 @@ import {AutoSaveConfiguration} from 'vs/platform/files/common/files';
import {FILE_EDITOR_INPUT_ID, VIEWLET_ID} from 'vs/workbench/parts/files/common/files';
import {FileTracker} from 'vs/workbench/parts/files/browser/fileTracker';
import {SaveParticipant} from 'vs/workbench/parts/files/common/editors/saveParticipant';
import {FileAssociations} from 'vs/workbench/parts/files/common/editors/fileAssociations';
import {FileEditorInput} from 'vs/workbench/parts/files/browser/editors/fileEditorInput';
import {TextFileEditor} from 'vs/workbench/parts/files/browser/editors/textFileEditor';
import {BinaryFileEditor} from 'vs/workbench/parts/files/browser/editors/binaryFileEditor';
......@@ -161,6 +162,11 @@ class FileEditorInputFactory implements IEditorInputFactory {
SaveParticipant
);
// Register File Associations
(<IWorkbenchContributionsRegistry>Registry.as(WorkbenchExtensions.Workbench)).registerWorkbenchContribution(
FileAssociations
);
// Configuration
let configurationRegistry = <IConfigurationRegistry>Registry.as(ConfigurationExtensions.Configuration);
......@@ -171,7 +177,6 @@ configurationRegistry.registerConfiguration({
'type': 'object',
'properties': {
'files.exclude': {
'id': 'glob-pattern',
'type': 'object',
'description': nls.localize('exclude', "Configure glob patterns for excluding files and folders."),
'default': { '**/.git': true, '**/.DS_Store': true },
......@@ -195,6 +200,10 @@ configurationRegistry.registerConfiguration({
]
}
},
'files.association': {
'type': 'object',
'description': nls.localize('association', "Configure file associations to languages (e.g. \"*.extension\": \"html\"). These have precedence over the default associations of the languages installed."),
},
'files.encoding': {
'type': 'string',
'enum': Object.keys(SUPPORTED_ENCODINGS),
......
/*---------------------------------------------------------------------------------------------
* 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 {IWorkbenchContribution} from 'vs/workbench/common/contributions';
import errors = require('vs/base/common/errors');
import mime = require('vs/base/common/mime');
import {IFilesConfiguration} from 'vs/platform/files/common/files';
import {IConfigurationService, IConfigurationServiceEvent, ConfigurationServiceEventTypes} from 'vs/platform/configuration/common/configuration';
import {IEventService} from 'vs/platform/event/common/event';
import {IModeService} from 'vs/editor/common/services/modeService';
// Register and update configured file associations
export class FileAssociations implements IWorkbenchContribution {
private toUnbind: { (): void; }[];
constructor(
@IConfigurationService private configurationService: IConfigurationService,
@IEventService private eventService: IEventService,
@IModeService private modeService: IModeService
) {
this.toUnbind = [];
this.registerListeners();
this.loadConfiguration();
}
private registerListeners(): void {
this.toUnbind.push(this.configurationService.addListener(ConfigurationServiceEventTypes.UPDATED, (e: IConfigurationServiceEvent) => this.onConfigurationChange(e.config)));
}
private loadConfiguration(): void {
this.configurationService.loadConfiguration().done((configuration: IFilesConfiguration) => {
this.onConfigurationChange(configuration);
}, errors.onUnexpectedError);
}
private onConfigurationChange(configuration: IFilesConfiguration): void {
if (configuration.files && configuration.files.association) {
Object.keys(configuration.files.association).forEach(pattern => {
mime.registerTextMimeByFilename(pattern, this.modeService.getMimeForMode(configuration.files.association[pattern]));
});
}
}
public getId(): string {
return 'vs.files.associations';
}
public dispose(): void {
while (this.toUnbind.length) {
this.toUnbind.pop()();
}
}
}
\ No newline at end of file
......@@ -171,7 +171,6 @@ configurationRegistry.registerConfiguration({
'type': 'object',
'properties': {
'search.exclude': {
'id': 'glob-pattern',
'type': 'object',
'description': nls.localize('exclude', "Configure glob patterns for excluding files and folders in searches. Inherits all glob patterns from the file.exclude setting."),
'default': { '**/node_modules': true, '**/bower_components': true },
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册