diff --git a/ide/web/lib/editors.dart b/ide/web/lib/editors.dart index fc1b1c742..548443afb 100644 --- a/ide/web/lib/editors.dart +++ b/ide/web/lib/editors.dart @@ -472,7 +472,7 @@ class _EditorState { if (manager.editorType(file.name) == EditorManager.EDITOR_TYPE_IMAGE) { return new Future.value(this); } else { - return file.getContents().then((text) { + return file.getContents().then((String text) { session = manager._aceManager.createEditSession(text, file.name); return this; }); @@ -536,14 +536,108 @@ class PreferenceContentProvider implements ContentProvider { final PreferenceStore _store; final String _filename; + // Prefix the store entry with "?/" to disallow any possible conflict with + // entries mirroring filenames. + String get _storeEntryName => "?/$_filename"; + StreamController _changeController = new StreamController.broadcast(); Stream get onChange => _changeController.stream; PreferenceContentProvider(this._store, this._filename); - Future read() => _store.getValue(_filename); + Future read() => _store.getValue(_storeEntryName); - Future write(String content) => _store.setValue(_filename, content); + Future write(String content) => _store.setValue(_storeEntryName, content); } +/** + * Defines a pseudo-File named [path] reading and writing to a preference store + * entry in [PreferenceStore] [_store]. + */ +class PreferenceFile implements File { + final String path; + + static Map> _storeEntryCaches = {}; + + PreferenceStore _store; + PreferenceContentProvider _contentProvider; + int _timestamp = 0; + + factory PreferenceFile(PreferenceStore store, String path) { + Map openEntries = _storeEntryCaches[store]; + + // Create a store entry cache for this store if not already created: + if (openEntries == null) openEntries = _storeEntryCaches[store] = {}; + + PreferenceFile entry = openEntries[path]; + if (entry != null) { + return entry; + } + + // Fall back to creating a new file (and storing a reference to it). + return openEntries[path] = new PreferenceFile._(store, path); + } + + PreferenceFile._(this._store, this.path) { + _contentProvider = new PreferenceContentProvider(_store, path); + } + + String get name => path.contains('/') + ? path.substring(path.lastIndexOf('/') + 1) : path; + + bool get isFile => true; + bool get isTopLevel => true; + html.Entry get entry => null; + Container get parent => null; + Project get project => null; + + int get timestamp => _timestamp; + + String get uuid => path; + + List getMarkers() => []; + + Future getContents() => _contentProvider.read().then((contents) => + (contents == null) ? "" : contents); + + Future setContents(String contents) { + return _contentProvider.write(contents).then((_) { + _timestamp = new DateTime.now().millisecondsSinceEpoch; + }); + } + + void clearMarkers([String type]) { } + + bool containedBy(Container container) => false; + + Marker createMarker(String type, int severity, String message, int lineNum, [int charStart = -1, int charEnd = -1]) { + return null; + } + + Future delete() => new Future.value(); + + int findMaxProblemSeverity() => 0; + + Future/**/ getBytes() => null; //new Future.value(_contents.codeUnits); + + dynamic getMetadata(String key, [defaultValue]) => null; + + bool isDerived() => false; + + bool isScmPrivate() => false; + + Future refresh() => new Future.value(); + + Future rename(String name) => new Future.value(); + + Future setBytes(List data) => new Future.value(); + + Future setBytesArrayBuffer(/*ArrayBuffer*/ bytes) => new Future.value(); + + void setMetadata(String key, data) { } + + Iterable traverse({bool includeDerived: true}) => [this]; + + Workspace get workspace => null; +} diff --git a/ide/web/lib/spark_flags.dart b/ide/web/lib/spark_flags.dart index 860fa6931..b34c01328 100644 --- a/ide/web/lib/spark_flags.dart +++ b/ide/web/lib/spark_flags.dart @@ -81,6 +81,10 @@ class SparkFlags { static bool get enableNewUsbApi => _flags['enable-new-usb-api'] == true && PlatformInfo.chromeVersion >= 40; + // TODO(ericarnold): Remove once editorconfig is complete + static bool get enableEditorConfig => + _flags['enable-editor-config'] == true; + /** * Add new flags to the set, possibly overwriting the existing values. * Maps are treated specially, updating the top-level map entries rather diff --git a/ide/web/spark.dart b/ide/web/spark.dart index 65de9afce..bf2e66ebd 100644 --- a/ide/web/spark.dart +++ b/ide/web/spark.dart @@ -509,6 +509,7 @@ abstract class Spark actionManager.registerAction(new PrevMarkerAction(this)); // TODO(devoncarew): TODO(devoncarew): Removed as per #2348. //actionManager.registerAction(new FileOpenAction(this)); + actionManager.registerAction(new GlobalSettingsAction(this)); actionManager.registerAction(new FileNewAction(this, getDialogElement('#fileNewDialog'))); actionManager.registerAction(new FolderNewAction(this, @@ -1447,6 +1448,21 @@ class FileOpenAction extends SparkAction { } } +class GlobalSettingsAction extends SparkAction { + PreferenceFile _file; + + GlobalSettingsAction(Spark spark) : super(spark, "global-settings", "Settings…") { + } + + void _invoke([Object context]) { + if (_file == null) { + _file = new PreferenceFile(spark.prefs.prefsStore, 'user.editorconfig'); + } + + spark.openEditor(_file); + } +} + class FileNewAction extends SparkActionWithDialog implements ContextAction { InputElement _nameElement; ws.Folder folder; diff --git a/ide/web/spark_polymer.dart b/ide/web/spark_polymer.dart index 2b515685d..25090b563 100644 --- a/ide/web/spark_polymer.dart +++ b/ide/web/spark_polymer.dart @@ -248,7 +248,8 @@ class SparkPolymer extends Spark { _bindButtonToAction('runButton', 'application-run'); _bindButtonToAction('leftNav', 'navigate-back'); _bindButtonToAction('rightNav', 'navigate-forward'); - _bindButtonToAction('settingsButton', 'settings'); + _bindButtonToAction('settingsButton', + SparkFlags.enableEditorConfig ? 'global-settings' : 'settings'); } //