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

multi-root workspace support, minimal patch #2117

Merged
merged 1 commit into from
Aug 7, 2018

Conversation

elaihau
Copy link
Contributor

@elaihau elaihau commented Jun 15, 2018

What is a workspace / workspace folder? It is a folder on the file system that serves as a container for:

  • workspace configuration: in sub-folder .theia
    • preferences, in .theia/settings.json
    • root folders list, in .theia/roots.json
  • optional content in the form of other files/folders

For backward compatibility and simplicity, a workspace folder that contains no explicit root folder list configuration will use its own folder as the single root. This permits using any folder as a workspace.
If subsequently an additional root folder is added to such a workspace, then both the newly added folder and the original implicit root are added to the root folders list configuration. Either can later be removed. If all roots are removed form the configuration, the workspace falls-back to using its own folder as implicit root.

This PR is the minimal patch for #1660

What's included in this PR:

  • a workspace's root folders list can be modified using the navigator context menu "add/remove folder" items to add or remove a folder
  • preference 'workspace.supportMultiRootWorkspace', with default value false, can be used to control if the context menu entries, used to modify the list of root folders, are shown or not. Since this is a new feature that is not supported by most Theia extensions yet, it probably makes sense to hide the UI by default for now
  • previously the "current root" was a static value, obtained by each extension that needs it, at the startup of a Theia client. To change it (e.g. to switch workspace), a restart of the client was required. For this feature we did not want to have to restart the client each time the list of root folders is updated, so we introduced a new "onWorkspaceRootChanged" event. Extensions that need to know when the list of root folders is modified can react to this event, e.g. to update their widgets. It's still necessary to reload the Theia frontend when switching workspace in a given tab or when closing a workspace.
  • the root folder list comprised of 1 to many folders can be displayed from the file navigator widget.
  • the root folders will be scanned for git repositories that the user can select, stage and commit files into.

What's not included:

  • users should have the choice of naming the workspace and choosing where to store the config file
  • preference extension should be able to handle the settings from multiple project
  • search-in-workspace and file-search extension should be able to perform the search across all folders in the workspace, and / or provide filtering mechanism to reduce the amount of information being displayed
  • output and problems widgets should display data from all root folders, and / or provide filtering mechanism to reduce the amount of information being displayed
  • task extension should be able to run tasks defined under all root folders
  • users should be able to open the terminal from any root folder in the workspace

Signed-off-by: elaihau liang.huang@ericsson.com

@elaihau elaihau force-pushed the T1660-1st branch 7 times, most recently from 37f2c75 to a98a351 Compare June 22, 2018 20:10
@elaihau elaihau changed the title [wip] multi-root workspace support, minimal patch multi-root workspace support, minimal patch Jun 22, 2018
@tsmaeder tsmaeder mentioned this pull request Jun 25, 2018
Copy link
Member

@paul-marechal paul-marechal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might have missed some things but it looks nice !

@@ -124,6 +131,10 @@ export class FileTreeModel extends TreeModelImpl implements LocationService {
await this.fileSystem.move(sourceUri, targetUri, { overwrite: true });
// to workaround https://github.com/Axosoft/nsfw/issues/42
this.refresh(target);

if (source.parent) {
this.refresh(source.parent);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This wasn't here before, is it a bug fix packed along the multi-root feature ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct me if i am wrong: i believe this is related to Axosoft/nsfw#42.
When files move from one root to the other, the code is not getting enough information to find out the source.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the explanation !

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you elaborate on how can I reproduce an issue without this code? refresh supposed to handle Axosoft/nsfw#42.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@elaihau could you comment on previous comment please

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I missed it. The way to reproduce it is having more than one root folders added to the workspace (say, folder1 and folder2), and moving a folder by drag-and-drop from folder2 to folder1, and same folder back from folder1 to folder2.

@@ -78,6 +90,38 @@ export class FileTree extends TreeImpl {
};
}

protected isVirtualRoot(node: CompositeTreeNode): boolean {
return node.parent === undefined && this.hasVirtualRoot && node.name === 'WorkspaceRoot';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to simply test the node based on a field it has ?
Like instead of checking if the tree knows if it holds a virtual root and check the name, have a field virtual and test like !node.parent && node.virtual. Or even !node.parent && VirtualNode.is(node) to match the way the check is done on other nodes ?

Maybe the tree doesn't have to know if it holds a virtual node, that's my thought. Tell me if I missed something.

Copy link
Contributor Author

@elaihau elaihau Jun 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe I don't event need the flag hasVirtualRoot in FileTree class. Like you said, the tree shouldn't have the knowledge pertaining to whether its root is virtual or not.

I will make the change you suggested.

await this.refreshWidget(workspaceChangeData.root, workspaceChangeData.roots, workspaceChangeData.workspaceConfigFile);
}

protected async refreshWidget(root: FileStat | undefined, roots: FileStat[], workspaceConfig: FileStat | undefined) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be better to just rely on roots and not root at the same time ?
I feel like the prototype should be:

refreshWidget(roots: FileStat[], workspaceConfig: FileStat | undefined)

this.startWatch(valid);
this.onWorkspaceRootChangeEmitter.fire(this._workspaceRootChange);
}
return Promise.resolve();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return;

@@ -19,7 +19,8 @@ export class WorkspaceUriLabelProviderContribution extends DefaultUriLabelProvid
constructor(@inject(WorkspaceService) wsService: WorkspaceService,
@inject(FileSystem) protected fileSystem: FileSystem) {
super();
wsService.root.then(root => {
wsService.workspaceRootChange.then(data => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is minor, but maybe this could be in an async postConstruct method, to convert this part to attribute injection like the documentation suggests to do ?

newConfig.roots = [workspaceFolderUri, rootUriToAdd];
}
await this.writeToWorkspaceFolder(newConfig);
return Promise.resolve();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can remove this line unless you think it adds clarity.

if (configContent) {
await this.writeToWorkspaceFolder({ roots: configContent.roots.filter(r => r !== rootUriToRemove) });
}
return Promise.resolve();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can remove this line unless you think it adds clarity.

@paul-marechal
Copy link
Member

Also for some reason, when I finish to build your branch, I see that there is a diff on yarn.lock, did you forget to check it in ?

firstRootNameDiv.textContent = rootName;
firstRootMsg.appendChild(firstRootNameDiv);
const remainder = document.createElement('span');
remainder.textContent = ' and its subfolders cannot be removed as it is the first root folder of the workspace.';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed, it may no longer be necessary to treat the first root folder in a special way, at least as far as removal goes.

@marcdumais-work
Copy link
Contributor

I tried this and was not able to switch workspace, using "File -> open". It worked when I first closed the current workspace and tried again.

@marcdumais-work
Copy link
Contributor

marcdumais-work commented Jun 27, 2018

@elaihau I think the description of this PR and commit message should be updated/enhanced. Here's my draft suggestion; we can discuss tomorrow.


What is a workspace / workspace folder? A folder on the file system that serves as a container for:

  • workspace configuration: in sub-folder .theia
    • preferences, in .theia/settings.json
    • root folders list, in .theia/roots.json
  • optionally content in the form of other files/folders

Theia and its extensions will generally only consider folders that are part of the root folders list. e.g. only those folders:

  • will be shown in the file navigator
  • will be scanned for git repositories that the user can select, stage and commit files into
  • [similarly for other extensions, to be updated later]

For extensions that are not yet updated to support multiple root folders, they will temporarily default to using the first configured root folder as fallback.

For backward compatibility and simplicity, a workspace folder that contains no explicit root folder list configuration will use its own folder as the single root. This permits using any folder as a workspace.
If subsequently an additional root folder is added to such a workspace, then both the newly added folder and the original implicit root are added to the root folders list configuration. Either can later be removed. If all roots are removed form the configuration, the workspace falls-back to using its own folder as implicit root.

What's in this PR:

  • a workspace's root folders list can be modified using the navigator context menu "add/remove folder" items to add or remove a folder
  • preference 'workspace.supportMultiRootWorkspace', with default value false, can be used to control if the context menu entries, used to modify the list of root folders, are shown or not. Since this is a new feature that is not supported by most Theia extensions yet, it probably makes sense to hide the UI by default for now
  • previously the "current root" was a static value, obtained by each extension that needs it, at the startup of a Theia client. To change it (e.g. to switch workspace), a restart of the client was required. For this feature we did not want to have to restart the client each time the list of root folders is updated, so we introduced a new "onWorkspaceRootChanged" event. Extensions that need to know when the list of root folders is modified can react to this event, e.g. to update their widgets. It's still necessary to reload the Theia frontend when switching workspace in a given tab or when closing a workspace.
  • extensions updated: workspace, git, & navigator

@marcdumais-work
Copy link
Contributor

marcdumais-work commented Jun 27, 2018

One little bug I noticed: If I enable the preference, I can see and execute the multi-root related commands. If I then disable the preference, the commands are still visible but disabled, until I restart the client. After client restart, the commands are no longer visible.

Update: not sure it's always the case, but when I just added the preference globally, I needed a client restart before I could see the commands in the context menu,

@lmcbout
Copy link
Contributor

lmcbout commented Jun 27, 2018 via email

@marcdumais-work
Copy link
Contributor

For the initial contribution, will we be able to remove the initial root folders !!

Yes, with a couple of minor adjustments to the current PR.

const parent = this.getNode(change.uri.parent.toString());
if (DirNode.is(parent) && parent.expanded) {
accept(parent);
const parentNodes = this.getNodes((node: FileStatNode) => change.uri.parent.toString() === node.uri.toString());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to look up by an id still? An idea was to have fast look up, now it seems to travers the whole tree to find a node.

@@ -204,6 +208,17 @@ export class TreeImpl implements Tree {
return id !== undefined ? this.nodes[id] : undefined;
}

getNodes(test: (node: TreeNode) => boolean): TreeNode[] {
Copy link
Member

@akosyakov akosyakov Jun 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like a very expensive operation. Is there a way to replace clients with getNode(id) by redesigning their tree structure?

Copy link
Member

@paul-marechal paul-marechal Jun 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then what id would you like to use ? Two different nodes can hold the same file uri (which was the old id).

example: I have the following roots:

- /home/x/projects/theia/
- /home/x/projects/

(it is something possible on vscode)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getNode(id) function is still in the interface. getNodes() is only called when there is a need. Having multiple roots opened in the file navigator means there could be more than one file associated with the same uri (like the scenario that @marechal-p described above).

Copy link
Member

@akosyakov akosyakov Jun 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suppose there is file://foo/bar/baz/x.txt file, and 2 workspaces file://foo and file://foo/bar.

If a file tree node have an id of form ${workspaceUri}:${fileUri} or something like that (so file://foo:file://foo/bar/baz/x.txt and file://foo/bar:file://foo/bar/baz/x.txt), then when a file is changed one can take a list of all workspaces, loop over them to create node ids and call getNode for each.

I assume that a list of workspaces will be short in most of cases (i have maximum 10 at the time), in comparison the file tree only for node_modules folder has over 800 children.

Copy link
Contributor Author

@elaihau elaihau Jun 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having an id in the form of ${workspaceUri}:${fileUri} is very close to I already did in this PR. With the ${workspaceUri} part of the id, we could easily figure out which root folder that the node comes from. No issues. :)

The getNodes() function is only called in the scenario where the ${workspaceUri}:${fileUri} is unavailable. Imagine we have file://foo:file://foo/bar/baz/x.txt and file://foo/bar:file://foo/bar/baz/x.txt in the workspace, and a user opens the file://foo/bar/baz/x.txt from the quick open (Ctrl + p). When this happens we have no context of this x.txt and therefore would have no idea which node to highlight in the file tree.

I see the reason that you think this operation is expensive. I would be happy if we could find a work around of calling getNodes().

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When this happens we have no context of this x.txt and therefore would have no idea which node to highlight in the file tree.

I don't understand how getNodes() makes difference? We always know workspace roots, so it is not an issue to create file://foo:file://foo/bar/baz/x.txt and file://foo/bar:file://foo/bar/baz/x.txt and call getNode for them.

Also sorry i meant ${workspaceRootUri}:${fileUri}, not ${workspaceUri}:...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concatenating the absolute root uris with the absolute file uris seems to be the most simple way to craft an id indeed. The getNodes was to make the loop you talked about part of the implementation, but thinking back it doesn't make really much sense for the Tree interface indeed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@akosyakov fixed

this.update();
const icon = await this.labelProvider.getIcon(root);
this.model.root = DirNode.createRoot(root, label, icon);
} else if (roots.length > 1) { // more than one folder
Copy link
Contributor Author

@elaihau elaihau Jun 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally having a single root in the workspace is just one scenario that multi-root workspace supports.
I actually don't have to have

if (roots.length === 1) { // only one folder is opened
...
else if (roots.length > 1) { // more than one folder

And the logic under the else if should be good enough to have the file tree displayed in both cases.

The reason that I am separating the one-root and multi-root is that, the file tree would collapse due to #1781 and the tree wouldn't look as nice as it should, in the multi-root setting.
I will keep the single root and multi root display logic separated until #1781 is fixed.

@marcdumais-work
Copy link
Contributor

marcdumais-work commented Jun 27, 2018

@elaihau as briefly discussed, the event added to notify extensions that the workspace has changed (added or removed a root folder) seems to be sent only in the frontend where it was triggered.So if we have more than one client using that workspace, the other one(s) will not know to update their widgets/state to reflect the change. e.g. the navigator of other clients will not show the latest roots

@elaihau elaihau force-pushed the T1660-1st branch 4 times, most recently from b8869ba to a0248a5 Compare June 29, 2018 14:52
@@ -121,6 +121,10 @@ export class FileTreeModel extends TreeModelImpl implements LocationService {
* Move the given source file or directory to the given target directory.
*/
async move(source: TreeNode, target: TreeNode) {
if (source.parent && source.parent.name === 'WorkspaceRoot') {
// do not support moving the root folder
Copy link
Contributor

@marcdumais-work marcdumais-work Jun 29, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That tests for any root folder, correct? If so, the comment could be adjusted. i.e. "the root" -> "a root"


if (validUris.length > 0 && this._root) {
const messageContainer = document.createElement('div');
messageContainer.textContent = 'Do you really want to remove the following roots and their subfolders from the workspace?';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would some users be scared that the content of the removed roots might be deleted? Since there is already an appropriate title on the dialog (Remove Folder From Workspace), maybe we could shorten the message and mention nothing is physically erased? e.g.:
"Remove the following folders from workspace? (note: nothing will be erased from disk)"

@elaihau
Copy link
Contributor Author

elaihau commented Jul 26, 2018

I find it is strange that settings for one project (workspace root) are considered to be workspace settings. In VS Code they solved it by separating workspace file from projects and a workspace file contain workspace settings next to roots, not a random project from a workspace. Each project should has their own settings and workspace its own independent from projects.

agreed. settings from different root folders should be separated.
like the commit message and the PR description mentioned, changes made to preferences package are not included. This PR is just the minimal patch of the #1660

There will be a separated PR in near future that addresses preference issues introduced by having multiple roots in the same workspace.
Right now, there are only two levels of prefs: UserPref & WorkspacePref. With the multi-root feature added to theia, I am going to add FolderPreferences, where settings defined in a project folder will only be applied to that particular folder only.

@elaihau elaihau force-pushed the T1660-1st branch 2 times, most recently from 7027290 to d153165 Compare July 26, 2018 18:45
if (rootStat) {
this._rootUri = rootStat.uri;
this.resolveReady();
}
});
this.workspaceService.onWorkspaceChanged(event => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

workspaceFolder cannot change right?

return CompositeTreeNode.is(node) && node.name === WorkspaceNode.name;
}

export function createRoot(children: DirNode[]): WorkspaceNode {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DirNode -> WorkspaceRootNode

) { }

registerCommands(commands: CommandRegistry): void {
commands.registerCommand(WorkspaceCommands.OPEN, {
isEnabled: () => true,
execute: () => this.showFileDialog()
execute: () => this.workspaceService.workspace.then(async data => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please extract a protected method showFileDialog as before

constructor(@inject(WorkspaceService) wsService: WorkspaceService,
@inject(FileSystem) protected fileSystem: FileSystem) {

constructor() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can be removed?

@akosyakov
Copy link
Member

akosyakov commented Jul 27, 2018

please rebase the PR, build failures probably are caused by a new release

please also look at #2117 (comment)

@elaihau
Copy link
Contributor Author

elaihau commented Jul 27, 2018

we should remove it and use _workspaceDescription.workspaceFolder instead, as a single source of truth

done.

please rebase the PR, build failures probably are caused by a new release

just did the rebase. let me see if it builds this time

@svenefftinge
Copy link
Contributor

There will be a separated PR in near future that addresses preference issues introduced by having multiple roots in the same workspace.

In that case, we could simply use roots[0] for now to obtain the location of preferences.

@elaihau
Copy link
Contributor Author

elaihau commented Jul 30, 2018

@svenefftinge

In that case, we could simply use roots[0] for now to obtain the location of preferences.
roots[0] is not necessarily where the preferences retrieves the settings. Think about this use case:

  1. user opens atom as the workspace folder
  2. user adds vsCode to the workspace. At this point, theia gets prefs from .../atom/.theia/settings.json. And roots.json looks like roots: ['atom', 'vsCode']. Everything is working properly.
  3. user removes atom from the workspace. roots.json becomes roots: ['vsCode'].
  4. user reloads theia. When this happens preferences extension would get prefs from .../vsCode/.theia/settings.json (instead of from .../atom/.theia/settings.json).

You might want to argue that "we could expose both atom and vsCode even if atom is removed from the workspace". If we do that, preferences extension works fine, however other extensions would get wrong roots data, e.g., navigator would render 2 roots as it doesn't know atom is not in the workspace anymore.

@svenefftinge
Copy link
Contributor

svenefftinge commented Jul 30, 2018

I don't really understand why it would be proper to use the atom-settings when working on the vsCode root? I think this is wrong and we need to support multiple settings, which are obtain using a URI as context. I.e. support settings per root.

But since you want to keep this PR small, we should tackle the preferences separately.
Therefore, I think we can go with the first root, what ever that is.

@elaihau
Copy link
Contributor Author

elaihau commented Jul 30, 2018

I don't really understand why it would be proper to use the atom-settings when working on the vsCode root? I think this is wrong and we need to support multiple settings, which are obtain using a URI as context. I.e. support settings per root.

In this use case atom-settings should be used as the workspace settings, while the vsCode-settings should be used as the folder settings. workspace settings are applied to the entire workspace, while folder settings are applied to the folder / project (i.e., atom or vsCode), and folder settings should override the workspace settings in the folder where they take effect. Therefore, settings under the atom are still important, even if atom is no longer in the workspace.

But since you want to keep this PR small, we should tackle the preferences separately.
Therefore, I think we can go with the first root, what ever that is.

That would introduce inconsistencies if we don't change preferences package much:

  1. when settings.json has atom and vsCode, workspace folder is atom, theia uses settings from atom
  2. when atom is removed, settings.json has vsCode, workspace folder becomes vsCode, theia still uses settings from atom.
  3. after user refreshes the browser, settings.json has vsCode, workspace folder stays vsCode, theia start using settings from vsCode.
  4. once user adds atom back, settings.json has vsCode and atom, workspace folder stays vsCode, theia uses settings from vsCode.

what i dislike is the 2) and 3) mentioned above, where theia settings silently change after the browser refresh.

@svenefftinge
Copy link
Contributor

I'm confused, we don't have something like folder settings, do we?
Also it sounds like you are distinguishing between the first root ("workspace folder") and the others. Why is that? I would say they are all just roots.

@elaihau
Copy link
Contributor Author

elaihau commented Jul 30, 2018

I'm confused, we don't have something like folder settings, do we?

at the moment we don't have folder settings. it is something that I am going to add.

Also it sounds like you are distinguishing between the first root ("workspace folder") and the others. Why is that? I would say they are all just roots.

because not all theia extensions are updated (as of today) to embrace the multi-root change. preferences is just one of them.

And this is why i think "go with the first root, what ever that is" wouldn't keep this PR small:

  1. we would have to refresh all the settings when atom gets removed from the workspace, as all the atom settings become obsolete. Also, do we want to implement something in preferences package in this PR, which would get changed in the next PR in a month?
  2. using the first root of the roots array breaks the rule of workspace folder never changes (until the next workspace gets opened), and makes the logic behind multi-root workspace conceptually difficult to understand:
    If atom is removed from the workspace, is the workspace folder still atom ?
    If the workspace folder becomes vsCode after atom is gone, should we move the roots.json from atom to vsCode?
    And what do we do to the roots.json that already exists under vsCode ? .../vsCode/.theia/roots.json might have been used for another workspace where vsCode is the workspace folder.

free feel to disagree: i think keeping the workspaceFolder consistent is the easiest to achieve the backward compatibility, keep the PR small, and make concept of workspace easy to understand.

we could discuss this in tomorrow's meeting, if you would be there :)

@elaihau elaihau force-pushed the T1660-1st branch 5 times, most recently from 71a12e5 to a0fe5c5 Compare August 3, 2018 12:24
@@ -74,14 +77,21 @@ export class GitRepositoryProvider {
}

async refresh(options?: GitRefreshOptions): Promise<void> {
const root = await this.workspaceService.root;
const roots = await this.workspaceService.roots;
const root = roots[0];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test for the first root should be removed. We are dealing with an array, which might be empty, but that's fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you are right. changes done.

const root = await this.workspaceService.root;
if (root) {
const rootUri = new URI(root.uri);
const workspaceFolder = (await this.workspaceService.roots)[0];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we put a TODO comment to all the locations where we just fetch the first root, so we don't miss them?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no worries :) I will review all references of WorkspaceService before creating my next PR

@svenefftinge
Copy link
Contributor

svenefftinge commented Aug 7, 2018

The tree navigation doesn't behave nicely, when I use the cursor keys going up:
aug-07-2018 11-16-34

@elaihau
Copy link
Contributor Author

elaihau commented Aug 7, 2018

@svenefftinge

I tested my change on top of the latest master, and looks like the tree navigation works. Please see the attached GIF. Could you please tell me how to reproduce the problem you observed? Maybe i have missed something in my test. Thanks !

peek 2018-08-07 09-00

@elaihau elaihau force-pushed the T1660-1st branch 2 times, most recently from 3ea11aa to d4896cf Compare August 7, 2018 14:31
What is a workspace / workspace folder? It is a folder on the file system that serves as a container for:

- workspace configuration: in sub-folder ".theia"
  - preferences, in ".theia/settings.json"
  - root folders list, in ".theia/roots.json"
- optionally content in the form of other files/folders

For backward compatibility and simplicity, a workspace folder that contains no explicit root folder list configuration will use its own folder as the single root. This permits using any folder as a workspace.
If subsequently an additional root folder is added to such a workspace, then both the newly added folder and the original implicit root are added to the root folders list configuration. Either can later be removed. If all roots are removed form the configuration, the workspace falls-back to using its own folder as implicit root.

This PR is the minimal patch for eclipse-theia#1660

What's included in this PR:
- a workspace's root folders list could be modified using the navigator context menu "add/remove folder" items to add or remove a folder
- preference 'workspace.supportMultiRootWorkspace', with default value false, can be used to control if the context menu entries, used to modify the list of root folders, are shown or not. Since this is a new feature that is not supported by most Theia extensions yet, it probably makes sense to hide the UI by default for now
- previously the "current root" was a static value, obtained by each extension that needs it, at the startup of a Theia client. To change it (e.g. to switch workspace), a restart of the client was required. For this feature we did not want to have to restart the client each time the list of root folders is updated, so we introduced a new "onWorkspaceRootChanged" event. Extensions that need to know when the list of root folders is modified can react to this event, e.g. to update their widgets. It's still necessary to reload the Theia frontend when switching workspace in a given tab or when closing a workspace.
- the root folder list comprised of 1 to many folders can be displayed from the file navigator widget.
- the root folders will be scanned for git repositories that the user can select, stage and commit files into.

What's not included:
- users should have the choice of naming the workspace and choosing where to store the config file
- preference extension should be able to handle the settings from multiple projects
- search-in-workspace and file-search extension should be able to perform the search across all folders in the workspace, and / or provide filtering mechanism to reduce the amount of information being displayed
- output and problems widgets should display data from all root folders, and / or provide filtering mechanism to reduce the amount of information being displayed
- task extension should be able to run tasks defined under all root folders
- users should be able to open the terminal from any root folder in the workspace

Signed-off-by: elaihau <liang.huang@ericsson.com>
@elaihau elaihau merged commit 80f402c into eclipse-theia:master Aug 7, 2018
@elaihau elaihau deleted the T1660-1st branch August 7, 2018 17:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants