-
Notifications
You must be signed in to change notification settings - Fork 183
SplitView Extension Migration Guide
As Kevin Dangoor pointed out in this Week's "Brackets Weekly", SplitView is a pretty big change under the hood. So this guide is here to help extension authors migrate their extensions to the new paradigm and what extension authors should do to maintain compatibility with Brackets.
For the most-part, Brackets will operate as it does today with a "current" view -- even though there is more than 1 view visible. Most of the changes will be transparent to extension authors but there are, however, a few things which extension authors should be aware of and a few things that extension authors should no longer do.
Here is a summary of the changes:
-
Editor
objects and ImageViewers are not immediate descendants of the#editor-holder
DOM node anymore. Extensions which manipulate the DOM at or under this node are probably going to stop working or cause stability and or usability issues for Brackets. -
Editors are not the only thing that live in the Main Viewing Area so
DocumentManger.getCurrentDocument()
andEditorManager.getCurrentFullEditor()
may returnnull
. This is not new but there may be more cases when this will happen so extension authors need to be prepared for this. -
Brackets will no longer have a single Working Set. Each
Pane
will manage a list of open files so extensions will need to identify which Working Set they wish to address when access the Working Set APIs. For alternatives to using Working Sets, see the section below on Working Set Alternatives. -
Working Sets will contain
File
objects, as they did in previous versions, but theFile
objects may not map toDocument
objects as they did in the past. Extension authors will need to be able to handle non-document objects in Working Sets. -
MainViewManager
manages allPane
objects and is the interface to accessing Views, Working Sets, etc... MostMainViewManager
APIs require aPaneId
to identify whichPane
to operate on. There are 2 PaneIds that have special meaning:ALL_PANES
andACTIVE_PANE
.ACTIVE_PANE
can be used on any API where aPaneId
is required. Some APIs, however, such as close, remove, find, etc... will take theALL_PANES
identifier to make traversal much easier. -
Custom View APIs are being deprecated in lieu of a View Factory Registry. Custom View providers need to construct a factory object that can create views for files.
These Events are Deprecated. Extension authors should migrate to the recommended event.
Event | Recommended event | Notes |
DocumentManager.workingSetAdd |
MainViewManager.paneViewAdd |
(1) |
DocumentManager.workingSetAddList |
MainViewManager.paneViewAddList |
(1) |
DocumentManager.workingSetRemove |
MainViewManager.paneViewRemove |
(1) |
DocumentManager.workingSetRemoveList |
MainViewManager.paneViewRemoveList |
(1) |
DocumentManager.workingSetSort |
MainViewManager.paneViewSort |
These APIs have been Deprecated and Extension Authors should migrate to the recommended API.
API | Recommended API |
DocumentManager.findInWorkingSet() |
MainViewManager.findView(MainViewManager.ALL_PANES) |
DocumentManager.getWorkingSet() |
MainViewManager.getViews(MainViewManager.ALL_PANES) or MainViewManager.getAllOpenFiles() |
DocumentManager.addToWorkingSet() |
MainViewManager.addView(MainViewManager.FOCUSED_PANE) |
DocumentManager.addListToWorkingSet() |
MainViewManager.addViews(MainViewManager.FOCUSED_PANE) |
DocumentManager.removeFromWorkingSet() |
MainViewManager.removeView(MainViewManager.ALL_PANES) |
DocumentManager.removeListFromWorkingSet() |
MainViewManager.removeViews(MainViewManager.ALL_PANES) |
DocumentManager.setCurrentDocument(doc) |
MainViewManager.open(MainViewManager.ACTIVE_PANE, doc.file) |
DocumentManager.closeAll() |
MainViewManager.closeAll(MainViewManager.ALL_PANES) |
DocumentManager.closeFullEditor() |
MainViewManager.close(MainViewManager.ALL_PANES) |
DocumentManager.beginDocumentNavigation() |
MainViewManager.beginTraversal() |
DocumentManager.finalizeDocumentNavigation() |
MainViewManager.endTraversal() |
DocumentManager.getNextPrevFile() |
MainViewManager.traverseViewsByMRU() |
These Public APIs are no longer in use and were identified as not being used by extensions. They have been removed from Brackets.
API |
sortWorkingSet() |
swapWorkingSetIndexes() |
findInWorkingSetAddedOrder() |
These APIs have been Deprecated and Extension Authors should migrate to the recommended API.
API | Recommended API | Notes |
DocumentManager.resizeEditor() |
WorkspaceManager.recomputeLayout() |
|
EditorManager.getCurrentlyViewedPath() |
MainViewManager.getCurrentlyViewedPath() |
EditorManager.getCurrentlyViewedPath() will return NULL if the current file is an image or otherwise not a document. |
EditorManager.setEditorHolder() |
Used by 1 or 2 extensions for unit tests but now does nothing. Unit tests can construct a create a MainViewManager and initialize it to a DOM element. See MainViewManager._init()
|
|
EditorManager.registerCustomViewer() |
Used by 1 or 2 extensions but does nothing. The preferred method is to create a View Factory that can create views of a file. | |
EditorManager.focusEditor() |
MainViewManager.focusActivePane() |
Extensions should be prepared that ImageViews or other Views are focusable in the new model. |
These Public APIs are no longer in use and were identified as not being used by extensions. They have been removed from Brackets.
API | Notes |
EditorManager.notifyPathDeleted() |
Was marked for internal use only but not private. Not used by extensions. |
EditorManager.showingCustomViewerForPath() |
Not used by extensions. There is no equivelent. |
These Events have been removed.
Event | Reccomended event | Notes |
EditorManager.currentFileChange |
MainViewManager.currentFileChange |
Not used by any registered extension |
These Private APIs have been removed but are being used by extensions. Extensions using these APIs will break.
API | Notes |
EditorManager._showCustomViewer() |
Register a View Factory then open the file that is to be used with the custom viewer. |
EditorManager._closeCustomViewer() |
No substition available. Extensions should register View Factories to create custom views and open a file assocatied with the factory object. Closing that view would be a close command on the current view. |
The following commands have been added to support File
objects.
Legacy Command | New Command | Notes |
FILE_ADD_TO_WORKING_SET |
CMD_ADD_TO_PANE_AND_OPEN |
The new command will resolve to a File object while the legacy command resolves to a Document object. |
FILE_OPEN |
CMD_OPEN |
The new command will resolve to a File object while the legacy command resolves to a Document object. |
Constant | Functionality | Notes |
MainViewManager.ALL_PANES |
The operation traverses all panes | Not all APIs will take this constant. See the API for details |
MainViewManager.ACTIVE_PANE |
The operation is performed only on the active pane |
APIs extension authors can use to get the list of files in the project in various forms that aren't Working Set specific:
Returns a list of all open files. This list will include all temporary views of files (those not in a working set), files opened that are not part of the project, images, files that are opened in an editor and files opened in custom viewers.
@type Array.<File>
Returns a list of all files in the project. Supports Filtering and inclusion of files opened in the working set which are not part of the projec.
@type Array.<File>
Returns a list of all open documents -- including documents which are in a workingset but not yet opened, documents which have been opened in inline editors but not part of a workingset and opened but not modified or added to any workingset.
@type Array.<Document>
EditorManager.registerCustomViewer()
made assumptions about the lifespan of a view and would only allow 1 view to be created which didn't scale to the new model so it was deprecated and no longer does anything.
Extension writers must now create a Factory object with this interface to construct custom views:
{
canOpenFile:function(path:string):boolean
openFile:function(path:string, pane:Pane):jQuery.Deferred()
}
Then register the factory by calling MainViewFactory.registerViewFactory()
View Factories will be able to crack a file URL to determine if they support creating a view for that particular file. ImageViewer, for example, responds by testing the file type for a known image type:
canOpenFile: function (fullPath) {
var lang = LanguageManager.getLanguageForPath(fullPath);
return (lang.getId() === "image");
}
URL cracking provides a fairly robust way to provide custom views for just about every file type, path or filename. View Factories are asked to crack URLs in a first-registered basis so there is no guaranteed order at this time.
{
getFile: function () @return {?File} File object that belongs to the view (may return null)
setVisible: function(visible:boolean) - shows or hides the view
updateLayout: function(forceRefresh:boolean) - tells the view to do ignore any cached layout data and do a complete layout of its cont
destroy: function() - called when the view is no longer needed.
hasFocus: function() - called to determine if the view has focus.
childHasFocus: function() - called to determine if a child component of the view has focus.
focus: function() - called to tell the view to take focus
getScrollPos: function() - called to get the current view scroll state. @return {Object=}
adjustScrollPos: function(state:Object=, heightDelta:number) - called to restore the scroll state and adjust the height by heightDelta
switchContainers: function($newContainer:jQuery} - called to reparent the view to a new container
getContainer: function() - called to get the current container @return {!jQuery} - the view's parent container
getViewState: function() @return {?*} - Called when the pane wants the view to save its view state. Return any data you needed to res
restoreViewState: function(!viewState:*) - Called to restore the view state. The viewState argument is whatever data was returned from
}
Here is a sample extension
For the most part, we expect that most extensions will continue to work as they do today. We have, however, identified a handful of extensions which do not work with Bracket's new architecture:
Extension | Why it breaks | Suggested remediation |
CodeOverview | Appnds nodes directly to #editor-holder
|
Could listen for EditorManager.activeEditorChange and append nodes to the $(Editor.getRootElement()) but would need to keep track of previous instances and remove them. |
MainWindow | Resizes nodes inside of #editor-holder
|
Just needs to resize #editor-holder and it should just work. |
Workdspaces | Resizes nodes inside of #editor-holder
|
Just needs to resize #editor-holder and it should just work. |
CharLImit | Appnds DOM nodes directly to #editor-holder
|
Could listen for EditorManager.activeEditorChange and append nodes to the $(Editor.getRootElement()) but would need to keep track of previous instances and remove them. |
EpicLinter | Assumes #editor-holder is the width of the editor |
Should use $(Editor.getRootElement()).width() instead. |
Shreder | Sets the width of #editor-holder to zero |
Unable to test with Release 0.42 or SplitView |
Brackets Tabs | Removes the working set and replaces it with tabs | The DOM node #working-set-header no longer exists so this extension fails. There are numerous other issues that would need to be fixed for this extension to work. |
Code Outline | Bases size based on #working-set-header which no longer exists |
Probably can just use $(#sidebar).width()
|
Font Viewer | Registers a Custom View for Font Files | Register a View Provider Factory for font files |
Brackets GIT |
|
The following Extension's Unit Tests will no longer work. Fixing these isn't critical, however, but extension authors should maintain their reliance on running unit tests regularly to ensure their extension continues to work normally. This list identifies those which will break.
Extension | Why it breaks | Suggested remediation | URL |
QuickRequire | Appends nodes directly to #editor-holder
|
Could listen for EditorManager.activeEditorChange and append nodes to the $(Editor.getRootElement()) but would need to keep track of previous instances and remove them. |
CodeOverview |
Simple JS Code Hints | Uses EditorManager.setEditorHolder()
|
Just use MainViewManager._init() . |
Simple JS Code Hints |
Brackets Type Script Code Intel | Uses EditorManager.setEditorHolder()
|
Just use MainViewManager._init() . |
Type Script Code Intel |
The following extensions were tested and didn't have major issues but some part of their functionality was broken due to the architecture change.
-
Brackets Vim - VIM
readme.md
references the ongoing SplitView work in core. Please let us know how it works for you. We tried your extension but the command:vsp
throws an RTE in both master without SplitView and this branch. Otherwise it appeared that VIM commands worked normally in the SplitView branch. -
Brackets Icons - Extension still works but icons are no longer displayed in the working set.
-
Brackets Files Icons - Extension still works but icons are no longer displayed in the working set.
-
Markdown Preview - Extension still works but no longer synchronizes the scroll position.
-
[Column Ruler)(https://github.com/lkcampbell/brackets-ruler) - Extension still works but doesn't show ruler correctly when the main view is split.
We encourage all extension authors to test their extensions even if they were not listed above. Extensions are one of the easiest ways to customize and contribute to Brackets so we'd like to thank you for your contributions and help make the transition as seamless and easy as possible. If there is anything missing from this migration guide or an API then please let the brackets team know.
Again, thank you for your contributions!