From 989bb861992f4bf5383842239a46897588e3e195 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 29 Jul 2015 11:27:24 -0700 Subject: [PATCH 01/11] Start work on custom scope -> filetypes configuration --- spec/grammars-spec.coffee | 5 +++ src/config-schema.coffee | 3 ++ src/grammar-registry.coffee | 87 ++++++++++++++++++++++++++++++++++++- src/tokenized-buffer.coffee | 4 +- 4 files changed, 96 insertions(+), 3 deletions(-) diff --git a/spec/grammars-spec.coffee b/spec/grammars-spec.coffee index cc975468f..ef48ec15b 100644 --- a/spec/grammars-spec.coffee +++ b/spec/grammars-spec.coffee @@ -110,6 +110,11 @@ describe "the `grammars` global", -> expect(-> atom.grammars.selectGrammar(null, '')).not.toThrow() expect(-> atom.grammars.selectGrammar(null, null)).not.toThrow() + describe "when the user has custom grammar filetypes", -> + it "considers the custom filetypes as well as those defined in the grammar", -> + atom.config.set('core.fileTypesByScope', 'source.ruby': ['Cheffile']) + expect(atom.grammars.selectGrammar('build/Cheffile', 'cookbook "postgres"').scopeName).toBe 'source.ruby' + describe ".removeGrammar(grammar)", -> it "removes the grammar, so it won't be returned by selectGrammar", -> grammar = atom.grammars.selectGrammar('foo.js') diff --git a/src/config-schema.coffee b/src/config-schema.coffee index d46cdf589..6ffcfa632 100644 --- a/src/config-schema.coffee +++ b/src/config-schema.coffee @@ -26,6 +26,9 @@ module.exports = default: [] items: type: 'string' + fileTypesByScope: + type: 'object' + default: {} themes: type: 'array' default: ['one-dark-ui', 'one-dark-syntax'] diff --git a/src/grammar-registry.coffee b/src/grammar-registry.coffee index 7b1ef823f..6a84b8ddd 100644 --- a/src/grammar-registry.coffee +++ b/src/grammar-registry.coffee @@ -1,7 +1,11 @@ +_ = require 'underscore-plus' {Emitter} = require 'event-kit' {includeDeprecatedAPIs, deprecate} = require 'grim' FirstMate = require 'first-mate' Token = require './token' +fs = require 'fs-plus' + +PathSplitRegex = new RegExp("[/.]") # Extended: Syntax class holding the grammars used for tokenizing. # @@ -39,7 +43,7 @@ class GrammarRegistry extends FirstMate.GrammarRegistry bestMatch = null highestScore = -Infinity for grammar in @grammars - score = grammar.getScore(filePath, fileContents) + score = @getGrammarScore(grammar, filePath, fileContents) if score > highestScore or not bestMatch? bestMatch = grammar highestScore = score @@ -47,6 +51,87 @@ class GrammarRegistry extends FirstMate.GrammarRegistry bestMatch = grammar unless grammar.bundledPackage bestMatch + # Extended: Returns a {Number} representing how well the grammar matches the + # `filePath` and `contents`. + getGrammarScore: (grammar, filePath, contents) -> + contents = fs.readFileSync(filePath, 'utf8') if not contents? and fs.isFileSync(filePath) + + if @grammarOverrideForPath(filePath) is grammar.scopeName + 2 + (filePath?.length ? 0) + else if @grammarMatchesContents(grammar, contents) + 1 + (filePath?.length ? 0) + else + @getGrammarPathScore(grammar, filePath) + + getGrammarPathScore: (grammar, filePath) -> + return -1 unless filePath + filePath = filePath.replace(/\\/g, '/') if process.platform is 'win32' + + pathComponents = filePath.toLowerCase().split(PathSplitRegex) + pathScore = -1 + + fileTypes = grammar.fileTypes + if customFileTypes = atom.config.get('core.fileTypesByScope')?[grammar.scopeName] + fileTypes = fileTypes.concat(customFileTypes) + + for fileType in fileTypes + fileTypeComponents = fileType.toLowerCase().split(PathSplitRegex) + pathSuffix = pathComponents[-fileTypeComponents.length..-1] + if _.isEqual(pathSuffix, fileTypeComponents) + pathScore = Math.max(pathScore, fileType.length) + pathScore + + grammarMatchesContents: (grammar, contents) -> + return false unless contents? and grammar.firstLineRegex? + + escaped = false + numberOfNewlinesInRegex = 0 + for character in grammar.firstLineRegex.source + switch character + when '\\' + escaped = !escaped + when 'n' + numberOfNewlinesInRegex++ if escaped + escaped = false + else + escaped = false + lines = contents.split('\n') + grammar.firstLineRegex.testSync(lines[0..numberOfNewlinesInRegex].join('\n')) + + # Public: Get the grammar override for the given file path. + # + # * `filePath` A {String} file path. + # + # Returns a {Grammar} or undefined. + grammarOverrideForPath: (filePath) -> + @grammarOverridesByPath[filePath] + + # Public: Set the grammar override for the given file path. + # + # * `filePath` A non-empty {String} file path. + # * `scopeName` A {String} such as `"source.js"`. + # + # Returns a {Grammar} or undefined. + setGrammarOverrideForPath: (filePath, scopeName) -> + if filePath + @grammarOverridesByPath[filePath] = scopeName + + # Public: Remove the grammar override for the given file path. + # + # * `filePath` A {String} file path. + # + # Returns undefined. + clearGrammarOverrideForPath: (filePath) -> + delete @grammarOverridesByPath[filePath] + undefined + + # Public: Remove all grammar overrides. + # + # Returns undefined. + clearGrammarOverrides: -> + @grammarOverridesByPath = {} + undefined + clearObservers: -> @off() if includeDeprecatedAPIs @emitter = new Emitter diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index b4b381c63..ca525c34c 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -68,7 +68,7 @@ class TokenizedBuffer extends Model if grammar.injectionSelector? @retokenizeLines() if @hasTokenForSelector(grammar.injectionSelector) else - newScore = grammar.getScore(@buffer.getPath(), @getGrammarSelectionContent()) + newScore = atom.grammars.getGrammarScore(grammar, @buffer.getPath(), @getGrammarSelectionContent()) @setGrammar(grammar, newScore) if newScore > @currentGrammarScore setGrammar: (grammar, score) -> @@ -76,7 +76,7 @@ class TokenizedBuffer extends Model @grammar = grammar @rootScopeDescriptor = new ScopeDescriptor(scopes: [@grammar.scopeName]) - @currentGrammarScore = score ? grammar.getScore(@buffer.getPath(), @getGrammarSelectionContent()) + @currentGrammarScore = score ? atom.grammars.getGrammarScore(grammar, @buffer.getPath(), @getGrammarSelectionContent()) @grammarUpdateDisposable?.dispose() @grammarUpdateDisposable = @grammar.onDidUpdate => @retokenizeLines() From 1ee382a4cb979d121b75ec68eaf0fe074aab9d65 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 29 Jul 2015 13:18:46 -0700 Subject: [PATCH 02/11] Add GrammarRegistry tests removed from first-mate --- spec/grammars-spec.coffee | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/spec/grammars-spec.coffee b/spec/grammars-spec.coffee index ef48ec15b..cc2f6bf6c 100644 --- a/spec/grammars-spec.coffee +++ b/spec/grammars-spec.coffee @@ -1,6 +1,7 @@ path = require 'path' fs = require 'fs-plus' temp = require 'temp' +GrammarRegistry = require '../src/grammar-registry' describe "the `grammars` global", -> beforeEach -> @@ -16,6 +17,9 @@ describe "the `grammars` global", -> waitsForPromise -> atom.packages.activatePackage('language-ruby') + waitsForPromise -> + atom.packages.activatePackage('language-git') + afterEach -> atom.packages.deactivatePackages() atom.packages.unloadPackages() @@ -30,6 +34,30 @@ describe "the `grammars` global", -> expect(grammars2.selectGrammar(filePath).name).toBe 'Ruby' describe ".selectGrammar(filePath)", -> + it "always returns a grammar", -> + registry = new GrammarRegistry() + expect(registry.selectGrammar().scopeName).toBe 'text.plain.null-grammar' + + it "selects the text.plain grammar over the null grammar", -> + expect(atom.grammars.selectGrammar('test.txt').scopeName).toBe 'text.plain' + + it "selects a grammar based on the file path case insensitively", -> + expect(atom.grammars.selectGrammar('/tmp/source.coffee').scopeName).toBe 'source.coffee' + expect(atom.grammars.selectGrammar('/tmp/source.COFFEE').scopeName).toBe 'source.coffee' + + describe "on Windows", -> + originalPlatform = null + + beforeEach -> + originalPlatform = process.platform + Object.defineProperty process, 'platform', value: 'win32' + + afterEach -> + Object.defineProperty process, 'platform', value: originalPlatform + + it "normalizes back slashes to forward slashes when matching the fileTypes", -> + expect(atom.grammars.selectGrammar('something\\.git\\config').scopeName).toBe 'source.git-config' + it "can use the filePath to load the correct grammar based on the grammar's filetype", -> waitsForPromise -> atom.packages.activatePackage('language-git') From aa8fb391aa681ab171224cf0fe71f8d3aac1781f Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 29 Jul 2015 13:58:54 -0700 Subject: [PATCH 03/11] Handle ties between custom and built-in grammar file types --- spec/grammars-spec.coffee | 16 ++++++++++++++-- src/grammar-registry.coffee | 5 ++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/spec/grammars-spec.coffee b/spec/grammars-spec.coffee index cc2f6bf6c..e2f8df568 100644 --- a/spec/grammars-spec.coffee +++ b/spec/grammars-spec.coffee @@ -138,11 +138,23 @@ describe "the `grammars` global", -> expect(-> atom.grammars.selectGrammar(null, '')).not.toThrow() expect(-> atom.grammars.selectGrammar(null, null)).not.toThrow() - describe "when the user has custom grammar filetypes", -> - it "considers the custom filetypes as well as those defined in the grammar", -> + describe "when the user has custom grammar file types", -> + it "considers the custom file types as well as those defined in the grammar", -> atom.config.set('core.fileTypesByScope', 'source.ruby': ['Cheffile']) expect(atom.grammars.selectGrammar('build/Cheffile', 'cookbook "postgres"').scopeName).toBe 'source.ruby' + it "favors user-defined file types over built-in ones of equal length", -> + atom.config.set('core.fileTypesByScope', + 'source.coffee': ['Rakefile'], + 'source.ruby': ['Cakefile'] + ) + expect(atom.grammars.selectGrammar('Rakefile', '').scopeName).toBe 'source.coffee' + expect(atom.grammars.selectGrammar('Cakefile', '').scopeName).toBe 'source.ruby' + + it "favors grammars with matching first-line-regexps even if custom file types match the file", -> + atom.config.set('core.fileTypesByScope', 'source.ruby': ['bootstrap']) + expect(atom.grammars.selectGrammar('bootstrap', '#!/usr/bin/env node').scopeName).toBe 'source.js' + describe ".removeGrammar(grammar)", -> it "removes the grammar, so it won't be returned by selectGrammar", -> grammar = atom.grammars.selectGrammar('foo.js') diff --git a/src/grammar-registry.coffee b/src/grammar-registry.coffee index 6a84b8ddd..4558dee8b 100644 --- a/src/grammar-registry.coffee +++ b/src/grammar-registry.coffee @@ -74,11 +74,14 @@ class GrammarRegistry extends FirstMate.GrammarRegistry if customFileTypes = atom.config.get('core.fileTypesByScope')?[grammar.scopeName] fileTypes = fileTypes.concat(customFileTypes) - for fileType in fileTypes + for fileType, i in fileTypes fileTypeComponents = fileType.toLowerCase().split(PathSplitRegex) pathSuffix = pathComponents[-fileTypeComponents.length..-1] if _.isEqual(pathSuffix, fileTypeComponents) pathScore = Math.max(pathScore, fileType.length) + if i >= grammar.fileTypes.length + pathScore += 0.5 + pathScore grammarMatchesContents: (grammar, contents) -> From 9e9f670ac37e22d1da7c45a29e9cfa0be2546c6e Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 29 Jul 2015 14:10:19 -0700 Subject: [PATCH 04/11] :shirt: Replace ! -> 'not' --- src/grammar-registry.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/grammar-registry.coffee b/src/grammar-registry.coffee index 4558dee8b..c7924843e 100644 --- a/src/grammar-registry.coffee +++ b/src/grammar-registry.coffee @@ -92,7 +92,7 @@ class GrammarRegistry extends FirstMate.GrammarRegistry for character in grammar.firstLineRegex.source switch character when '\\' - escaped = !escaped + escaped = not escaped when 'n' numberOfNewlinesInRegex++ if escaped escaped = false From 84f72c880a8f7976d03c8048f145cedf74d8da9f Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 30 Jul 2015 18:28:06 -0700 Subject: [PATCH 05/11] Config - don't allow setting key-paths inside of strings, arrays, etc --- spec/config-spec.coffee | 13 +++++++++++-- src/config.coffee | 14 +++++++++++--- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/spec/config-spec.coffee b/spec/config-spec.coffee index b75a121a1..cd6e3651d 100644 --- a/spec/config-spec.coffee +++ b/spec/config-spec.coffee @@ -1142,8 +1142,8 @@ describe "Config", -> type: 'integer' default: 12 - expect(atom.config.getSchema('foo.baz')).toBeUndefined() - expect(atom.config.getSchema('foo.bar.anInt.baz')).toBeUndefined() + expect(atom.config.getSchema('foo.baz')).toBe(null) + expect(atom.config.getSchema('foo.bar.anInt.baz')).toBe(false) it "respects the schema for scoped settings", -> schema = @@ -1380,6 +1380,10 @@ describe "Config", -> expect(atom.config.set('foo.bar.aString', nope: 'nope')).toBe false expect(atom.config.get('foo.bar.aString')).toBe 'ok' + it 'does not allow setting children of that key-path', -> + expect(atom.config.set('foo.bar.aString.something', 123)).toBe false + expect(atom.config.get('foo.bar.aString')).toBe 'ok' + describe 'when the schema has a "maximumLength" key', -> it "trims the string to be no longer than the specified maximum", -> schema = @@ -1438,6 +1442,11 @@ describe "Config", -> atom.config.set 'foo.bar', ['2', '3', '4'] expect(atom.config.get('foo.bar')).toEqual [2, 3, 4] + it 'does not allow setting children of that key-path', -> + expect(atom.config.set('foo.bar.child', 123)).toBe false + expect(atom.config.set('foo.bar.child.grandchild', 123)).toBe false + expect(atom.config.get('foo.bar')).toEqual [1, 2, 3] + describe 'when the value has a "color" type', -> beforeEach -> schema = diff --git a/src/config.coffee b/src/config.coffee index b713bd024..c3983fcbe 100644 --- a/src/config.coffee +++ b/src/config.coffee @@ -665,12 +665,18 @@ class Config # # Returns an {Object} eg. `{type: 'integer', default: 23, minimum: 1}`. # Returns `null` when the keyPath has no schema specified. + # Returns `false` when the key-path is not accessible from the root schema. getSchema: (keyPath) -> keys = splitKeyPath(keyPath) schema = @schema for key in keys - break unless schema? - schema = schema.properties?[key] + if schema.type is 'object' + childSchema = schema.properties?[key] + unless childSchema? + return null + else + return false + schema = childSchema schema # Extended: Get the {String} path to the config file being used. @@ -948,7 +954,9 @@ class Config catch e undefined else - value = @constructor.executeSchemaEnforcers(keyPath, value, schema) if schema = @getSchema(keyPath) + if (schema = @getSchema(keyPath))? + throw new Error("Illegal key path #{keyPath}") if schema is false + value = @constructor.executeSchemaEnforcers(keyPath, value, schema) value # When the schema is changed / added, there may be values set in the config From fbd684926eecaa349ad4a7c2790cc391ee98281b Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 30 Jul 2015 18:28:41 -0700 Subject: [PATCH 06/11] Config - Support additionalProperties field of object schemas --- spec/config-spec.coffee | 41 +++++++++++++++++++++++++++++++++++++++++ src/config.coffee | 20 +++++++++++++++++--- 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/spec/config-spec.coffee b/spec/config-spec.coffee index cd6e3651d..1821b7e01 100644 --- a/spec/config-spec.coffee +++ b/spec/config-spec.coffee @@ -1429,6 +1429,47 @@ describe "Config", -> expect(atom.config.get('foo.bar.anInt')).toEqual 12 expect(atom.config.get('foo.bar.nestedObject.nestedBool')).toEqual true + describe "when the value has additionalProperties set to false", -> + it 'does not allow other properties to be set on the object', -> + atom.config.setSchema('foo.bar', + type: 'object' + properties: + anInt: + type: 'integer' + default: 12 + additionalProperties: false + ) + + expect(atom.config.set('foo.bar', {anInt: 5, somethingElse: 'ok'})).toBe true + expect(atom.config.get('foo.bar.anInt')).toBe 5 + expect(atom.config.get('foo.bar.somethingElse')).toBeUndefined() + + expect(atom.config.set('foo.bar.somethingElse', {anInt: 5})).toBe false + expect(atom.config.get('foo.bar.somethingElse')).toBeUndefined() + + describe 'when the value has an additionalProperties schema', -> + it 'validates properties of the object against that schema', -> + atom.config.setSchema('foo.bar', + type: 'object' + properties: + anInt: + type: 'integer' + default: 12 + additionalProperties: + type: 'string' + ) + + expect(atom.config.set('foo.bar', {anInt: 5, somethingElse: 'ok'})).toBe true + expect(atom.config.get('foo.bar.anInt')).toBe 5 + expect(atom.config.get('foo.bar.somethingElse')).toBe 'ok' + + expect(atom.config.set('foo.bar.somethingElse', 7)).toBe false + expect(atom.config.get('foo.bar.somethingElse')).toBe 'ok' + + expect(atom.config.set('foo.bar', {anInt: 6, somethingElse: 7})).toBe true + expect(atom.config.get('foo.bar.anInt')).toBe 6 + expect(atom.config.get('foo.bar.somethingElse')).toBe undefined + describe 'when the value has an "array" type', -> beforeEach -> schema = diff --git a/src/config.coffee b/src/config.coffee index c3983fcbe..f26599a0b 100644 --- a/src/config.coffee +++ b/src/config.coffee @@ -673,7 +673,12 @@ class Config if schema.type is 'object' childSchema = schema.properties?[key] unless childSchema? - return null + if isPlainObject(schema.additionalProperties) + childSchema = schema.additionalProperties + else if schema.additionalProperties is false + return false + else + return null else return false schema = childSchema @@ -1085,17 +1090,26 @@ Config.addSchemaEnforcers throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} must be an object") unless isPlainObject(value) return value unless schema.properties? + defaultChildSchema = null + allowsAdditionalProperties = true + if isPlainObject(schema.additionalProperties) + defaultChildSchema = schema.additionalProperties + if schema.additionalProperties is false + allowsAdditionalProperties = false + newValue = {} for prop, propValue of value - childSchema = schema.properties[prop] + childSchema = schema.properties[prop] ? defaultChildSchema if childSchema? try newValue[prop] = @executeSchemaEnforcers("#{keyPath}.#{prop}", propValue, childSchema) catch error console.warn "Error setting item in object: #{error.message}" - else + else if allowsAdditionalProperties # Just pass through un-schema'd values newValue[prop] = propValue + else + console.warn "Illegal object key: #{keyPath}.#{prop}" newValue From 506dfc863cab3b4b84321d193f9c72f86441c897 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 30 Jul 2015 18:29:01 -0700 Subject: [PATCH 07/11] Require fileTypesByScope entries to be arrays of strings --- src/config-schema.coffee | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/config-schema.coffee b/src/config-schema.coffee index 6ffcfa632..93d0dcdc2 100644 --- a/src/config-schema.coffee +++ b/src/config-schema.coffee @@ -29,6 +29,10 @@ module.exports = fileTypesByScope: type: 'object' default: {} + additionalProperties: + type: 'array' + items: + type: 'string' themes: type: 'array' default: ['one-dark-ui', 'one-dark-syntax'] From 5f620fb73919a5ac94b2f401e03e7ca42c19e02e Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 12 Aug 2015 16:52:25 -0700 Subject: [PATCH 08/11] Config::getSchema - use null to represent inaccessible key path --- spec/config-spec.coffee | 4 ++-- src/config.coffee | 19 +++++++++++-------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/spec/config-spec.coffee b/spec/config-spec.coffee index 1821b7e01..3b7bd6061 100644 --- a/spec/config-spec.coffee +++ b/spec/config-spec.coffee @@ -1142,8 +1142,8 @@ describe "Config", -> type: 'integer' default: 12 - expect(atom.config.getSchema('foo.baz')).toBe(null) - expect(atom.config.getSchema('foo.bar.anInt.baz')).toBe(false) + expect(atom.config.getSchema('foo.baz')).toEqual {type: 'any'} + expect(atom.config.getSchema('foo.bar.anInt.baz')).toBe(null) it "respects the schema for scoped settings", -> schema = diff --git a/src/config.coffee b/src/config.coffee index f26599a0b..7c6dc8286 100644 --- a/src/config.coffee +++ b/src/config.coffee @@ -664,8 +664,8 @@ class Config # * `keyPath` The {String} name of the key. # # Returns an {Object} eg. `{type: 'integer', default: 23, minimum: 1}`. - # Returns `null` when the keyPath has no schema specified. - # Returns `false` when the key-path is not accessible from the root schema. + # Returns `null` when the keyPath has no schema specified, but is accessible + # from the root schema. getSchema: (keyPath) -> keys = splitKeyPath(keyPath) schema = @schema @@ -676,11 +676,11 @@ class Config if isPlainObject(schema.additionalProperties) childSchema = schema.additionalProperties else if schema.additionalProperties is false - return false - else return null + else + return {type: 'any'} else - return false + return null schema = childSchema schema @@ -959,10 +959,9 @@ class Config catch e undefined else - if (schema = @getSchema(keyPath))? + unless (schema = @getSchema(keyPath))? throw new Error("Illegal key path #{keyPath}") if schema is false - value = @constructor.executeSchemaEnforcers(keyPath, value, schema) - value + @constructor.executeSchemaEnforcers(keyPath, value, schema) # When the schema is changed / added, there may be values set in the config # that do not conform to the schema. This will reset make them conform. @@ -1040,6 +1039,10 @@ class Config # order of specification. Then the `*` enforcers will be run, in order of # specification. Config.addSchemaEnforcers + 'any': + coerce: (keyPath, value, schema) -> + value + 'integer': coerce: (keyPath, value, schema) -> value = parseInt(value) From 62aaadbfb681d3c8ea7a2ca6a88c7f2df88aaa92 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 12 Aug 2015 17:26:44 -0700 Subject: [PATCH 09/11] :arrow_up: settings-view --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ac6a00a20..825f335a7 100644 --- a/package.json +++ b/package.json @@ -108,7 +108,7 @@ "open-on-github": "0.37.0", "package-generator": "0.40.0", "release-notes": "0.53.0", - "settings-view": "0.211.2", + "settings-view": "0.213.1", "snippets": "0.95.0", "spell-check": "0.59.0", "status-bar": "0.75.1", From 2493da0a8411f7b954fdbaffb1f919488e2a681b Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 12 Aug 2015 17:55:19 -0700 Subject: [PATCH 10/11] Rename fileTypesByScope -> customFileTypes --- spec/grammars-spec.coffee | 6 +++--- src/config-schema.coffee | 2 +- src/grammar-registry.coffee | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/grammars-spec.coffee b/spec/grammars-spec.coffee index e2f8df568..960ce7d52 100644 --- a/spec/grammars-spec.coffee +++ b/spec/grammars-spec.coffee @@ -140,11 +140,11 @@ describe "the `grammars` global", -> describe "when the user has custom grammar file types", -> it "considers the custom file types as well as those defined in the grammar", -> - atom.config.set('core.fileTypesByScope', 'source.ruby': ['Cheffile']) + atom.config.set('core.customFileTypes', 'source.ruby': ['Cheffile']) expect(atom.grammars.selectGrammar('build/Cheffile', 'cookbook "postgres"').scopeName).toBe 'source.ruby' it "favors user-defined file types over built-in ones of equal length", -> - atom.config.set('core.fileTypesByScope', + atom.config.set('core.customFileTypes', 'source.coffee': ['Rakefile'], 'source.ruby': ['Cakefile'] ) @@ -152,7 +152,7 @@ describe "the `grammars` global", -> expect(atom.grammars.selectGrammar('Cakefile', '').scopeName).toBe 'source.ruby' it "favors grammars with matching first-line-regexps even if custom file types match the file", -> - atom.config.set('core.fileTypesByScope', 'source.ruby': ['bootstrap']) + atom.config.set('core.customFileTypes', 'source.ruby': ['bootstrap']) expect(atom.grammars.selectGrammar('bootstrap', '#!/usr/bin/env node').scopeName).toBe 'source.js' describe ".removeGrammar(grammar)", -> diff --git a/src/config-schema.coffee b/src/config-schema.coffee index 93d0dcdc2..334437618 100644 --- a/src/config-schema.coffee +++ b/src/config-schema.coffee @@ -26,7 +26,7 @@ module.exports = default: [] items: type: 'string' - fileTypesByScope: + customFileTypes: type: 'object' default: {} additionalProperties: diff --git a/src/grammar-registry.coffee b/src/grammar-registry.coffee index c7924843e..033595dad 100644 --- a/src/grammar-registry.coffee +++ b/src/grammar-registry.coffee @@ -71,7 +71,7 @@ class GrammarRegistry extends FirstMate.GrammarRegistry pathScore = -1 fileTypes = grammar.fileTypes - if customFileTypes = atom.config.get('core.fileTypesByScope')?[grammar.scopeName] + if customFileTypes = atom.config.get('core.customFileTypes')?[grammar.scopeName] fileTypes = fileTypes.concat(customFileTypes) for fileType, i in fileTypes From 0203438669e5ef10a3d048d72e2a005ca84189eb Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 12 Aug 2015 18:04:52 -0700 Subject: [PATCH 11/11] Add description for customFileTypes in schema --- src/config-schema.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/config-schema.coffee b/src/config-schema.coffee index 334437618..27f436e09 100644 --- a/src/config-schema.coffee +++ b/src/config-schema.coffee @@ -29,6 +29,7 @@ module.exports = customFileTypes: type: 'object' default: {} + description: 'Associates scope names (e.g. "source.js") with arrays of file extensions and file names (e.g. ["Somefile", ".js2"])' additionalProperties: type: 'array' items: