Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Nav toolbar - impements #9418 #31162

Closed
wants to merge 13 commits into from

Conversation

mihailik
Copy link
Contributor

@mihailik mihailik commented Jul 20, 2017

Fully functional, but not very well styled navigational toolbar, as described in #9418 Feature Request : Navigation Bar like Visual Studio or Eclipse

screen shot 2017-07-25 at 08 17 47

Clicking on the breadcrumb element scrolls editor and places cursor onto it. Also flashes the symbol momentarily. Neat navigation!

On startup it takes a little while to appear (language service need to initialise). Then it follows cursor movement and editing of course!

By relying on standard DocumentSymbolProvider, it just works with whatever lexical model current editor uses. Picks up deep parsing features in TypeScript, and uses dumber match editing JSON.

Missing pieces

Styling is beyond naive: just applying CSS within code. I'm keen to do it properly, but need guidance please!

Diff mode only populates navbar for edited panel, the original code isn't decorated with navbar. It looks silly on screen, and could be helpful to enable in Diff/original too.

Everything is in one file -- should I separate the logic from that codeEditor somewhere else? Any guidance is welcome!

No tests please guide me what's the best approach here: where should tests go?

More features to add

  • Hover over symbol name in navbar can highlight its location in editor
  • Icons for different symbol kinds
  • Use further language service features for tooltips
  • Allow dropdown-like functionality for selecting and navigating to sibling symbols

@mention-bot
Copy link

@mihailik, thanks for your PR! By analyzing the history of the files in this pull request, we identified @alexandrudima and @jrieken to be potential reviewers.

@mihailik
Copy link
Contributor Author

Updated screenshot.

@RobertoMalatesta
Copy link

It would be nice to see it on nightly.

@jrieken
Copy link
Member

jrieken commented Sep 25, 2017

This is pretty cool and something I have been missing. Indeed, my office was opposite of the guy that did it for Eclipse. You are on the right path but there are some bits missing:

  • Don't trust the data. The API fails to spec how document symbols should actually look like and some language extensions don't create ranges that contain each other, e.g C# is one of them and its symbol ranges only enclose the identifier of a symbol. That means the range won't tell you that a method is enclosed by a class... We have this on our radar and as part of Feature request: symbols tree view #5605 we need to either refine the existing API and create a new API that allows to have a symbol tree (either computed by range or as a tree)

  • From the architectural point of view something like this must be in editor/contrib and it must use the editor through its API. Some of those you don't have yet... Also styling, accessibility, icons and all those little things...

Dude, this is pretty cool and I am existing to having this, tho it is still a bit of work

@jrieken
Copy link
Member

jrieken commented Sep 25, 2017

I did fork the API work to #34968

@mihailik
Copy link
Contributor Author

mihailik commented Sep 25, 2017

Thanks @jrieken -- agree on all points! In fact I tried to handle tree/symbol/range structure on a local branch, but turned into a rabbit hole, ground it to a halt.

Cleaner API + some feedback = I am excited to push ahead!

I assume while waiting for the #34968 API update, I should rearrange the code/styling. If you give me some clues, point towards existing code to copy from I'll set out to work on that.

@jrieken
Copy link
Member

jrieken commented Sep 25, 2017

It does need some input from @alexandrudima to support contributing a widget to the editor that pushes down all content, like like a north|east|south|west-widget. That needs editor support and @alexandrudima can provide guidance.

@microsoft microsoft deleted a comment from msftclas Sep 27, 2017
@alexdima
Copy link
Member

To keep things clean, it would be quite important that the logic is moved out of codeEditor.ts and into a new folder under src/vs/editor/contrib. The reason is that this should be an optional feature without which the editor core can continue to function. i.e. this logic should be implemented as an editor contribution and various users of the code editor (including the debug repl or the settings or the standalone monaco editor) can choose to include the contribution or not.

To achieve this, there needs to be a new IEditorContribution defined in the /contrib/, perhaps similar to the code lens contribution. e.g. https://github.com/Microsoft/vscode/blob/0e46aa671c9f5365514b376d9fb47a44e6cd48f6/src/vs/editor/contrib/codelens/browser/codelensController.ts#L23

IEditorContributions get instantiated once per editor and they receive the ICodeEditor as the first argument in their ctor. So, an IEditorContribution shares the lifecycle of codeEditor.ts.

Now, this contribution needs new APIs from ICodeEditor. New methods must be added to ICodeEditor (similar in spirit with addContentWidget or addOverlayWidget), that must express the fact that a region is to be reserved at the top, left, bottom or right (or it can use north, south, east, west). The API can be spec'd as is needed, perhaps the contribution adds its dom node and the exact size in pixels it wishes to take.

Then, it would be the responsibility of CodeEditorWidget to implement this method and ensure that space is reserved correctly and the layout methods are not confused by this foreign element.

@mihailik
Copy link
Contributor Author

mihailik commented Oct 13, 2017

@alexandrudima — I want to simplify the widget-side design:

  • allow only placing bar-like widgets at the top;
  • bar height is dictated by editor, not requested by widget;
  • if multiple bars appear, they have to sit side-by-side rather than extend arbitrarily down.

The trouble with more generic approach, it affects too many places and would be too risky a PR to pass.

The more generic addEdgeWidget becomes lots more complex than addOverlayWidget. Overlays don't affect the editing content layout, so layout flows one way from editor to widgets via ViewConfigurationChangedEvent. If edge bars allowed to request size, layout becomes a complex 2-way negotiation.

Higher concern is that allowing decorative crust on all 4 edges could lead away from uncluttered design objective of VSCode.


With simplified design, the new ICodeEditor.addToolbarWidget will have DOM node as a parameter. But no edge/side preference, no size. CodeEditorWidget will have a binary decision: either allocate toolbar space, or not.

And ToolbarWidgets responsibility is to put toolbar widget(s) in the allocated rectangle. Which in fact would only host navbar for the medium future.

@alexdima
Copy link
Member

Here is what I had in mind:

const enum EdgeWidgetPosition { N, E, S, W }

interface IEdgeWidget {
    getId(): string;
    getDomNode(): HTMLElement;
    /** returns the location where the widget would like to sit */
    getPosition(): EdgeWidgetPosition;
    /** returns the width (for E or W widgets) or the height (for N or S widgets) in px */
    getSize(): number;
}

interface ICodeEditor {
    ...
    /** will call getPosition() and getSize() once to layout the widget and will insert getDomNode() to the DOM. */
    addEdgeWidget(widget: IEdgeWidget): void;
   /** will call getPosition() and getSize() once to layout the widget. */
   layoutEdgeWidget(widget: IEdgeWidget): void;
   /** will remove the dom node from the DOM */
   removeEdgeWidget(widget: IEdgeWidget): void;
}

Implementation wise, on the code editor side, a separate object can be allocated per contributed widget:

interface IEdgeWidgetData {
    domNode: HTMLElement;
    position: EdgeWidgetPosition;
    size: number;
    source: IEdgeWidget;
}

class CodeEditorWidget implements ICodeEditor {
  ...
  private _edgeWidgets: IEdgeWidgetData[];

  ...

   // - to add an edge widget, a new `IEdgeWidgetData` is pushed onto `_edgeWidgets` and an editor layout is triggered (getPosition() and getSize() are called once on the widget), the dom node is fetched via getDomNode() and stored in `domNode` and added to the DOM.
   // - to layout an edge widget, the widget is located in `_edgeWidgets` and an editor layout is triggered (getPosition() and getSize() are called once on the widget)
   // - to remove an edge widget, the `domNode` is removed from the DOM.

 ...
 
  // layouting needs to loop over contributed edge widgets, in the order they were contributed
  // and split them in the 4 cases (N, E, S, W)
  // Then, the dom node are absolutely positioned and positions are computed
  // Finally, the remaining width and height is the one that is somehow passed into the `Configuration` object. This might require a bit of refactorings to work smoothly.
}

@alexdima alexdima added this to the Backlog milestone Nov 14, 2017
@mihailik
Copy link
Contributor Author

Starting anew, going with IEdgeWidget outlined by @alexandrudima.

There are two similar things: IContentWidget and IOverlayWidget.

Can't see what was meant by 'contribution' in here, so will press ahead with approach closely following IContentWidget. My current worry it may snowball and affect lots of files in many directories.

P.S. The old branch is preserved as nav-toolbar-save

@mihailik
Copy link
Contributor Author

@alexandrudima drudima what I'm really struggling to figure is the lifecycle and ownership of EditorLayoutInfo.

When edge widget is added (say a toolbar) it must squeeze the height of the editor content area.

Stepping through the code it goes in EditLayoutProvider.compute. It digests sizes, metrics, constraints and allocates editor-specific sizes, including contentWidth, contentHeight and such.

Does it make sense, am I on the right track?

@alexdima alexdima changed the title Nav toolbar - impements #9418 [WIP] Nav toolbar - impements #9418 Apr 6, 2018
@jrieken jrieken closed this Aug 15, 2018
@github-actions github-actions bot locked and limited conversation to collaborators Mar 27, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants