Skip to content

Fix issues surrounding persisted workspaces. #18

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

Merged
merged 1 commit into from
Nov 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/vs/base/common/uri.ts
Original file line number Diff line number Diff line change
Expand Up @@ -701,3 +701,13 @@ function percentDecode(str: string): string {
}
return str.replace(_rEncodedAsHex, (match) => decodeURIComponentGraceful(match));
}

/**
* Encode a path for opening via the folder or workspace query parameter. This
* preserves slashes so it can be edited by hand more easily.
*
* @author coder
*/
export const encodePath = (path: string): string => {
return path.split('/').map((p) => encodeURIComponent(p)).join('/');
};
20 changes: 5 additions & 15 deletions src/vs/code/browser/workbench/workbench.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { Emitter, Event } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { Schemas } from 'vs/base/common/network';
import { isEqual } from 'vs/base/common/resources';
import { URI, UriComponents } from 'vs/base/common/uri';
import { encodePath, URI, UriComponents } from 'vs/base/common/uri';
import { generateUuid } from 'vs/base/common/uuid';
import { request } from 'vs/base/parts/request/browser/request';
import { localize } from 'vs/nls';
Expand All @@ -37,16 +37,6 @@ function doCreateUri(path: string, queryValues: Map<string, string>): URI {
return URI.parse(window.location.href).with({ path, query });
}

/**
* Encode a path for opening via the folder or workspace query parameter. This
* preserves slashes so it can be edited by hand more easily.
*
* @author coder
*/
export const encodePath = (path: string): string => {
return path.split('/').map((p) => encodeURIComponent(p)).join('/');
};

interface ICredential {
service: string;
account: string;
Expand Down Expand Up @@ -454,11 +444,11 @@ class WindowIndicator implements IWindowIndicator {
* @author coder
*/
const toRemote = (value: string): string => {
if (value.startsWith("/")) {
return "vscode-remote://" + value;
if (value.startsWith('/')) {
return 'vscode-remote://' + value;
}
return value
}
return value;
};

const query = new URL(document.location.href).searchParams;
query.forEach((value, key) => {
Expand Down
64 changes: 61 additions & 3 deletions src/vs/workbench/browser/web.main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteA
import { IFileService } from 'vs/platform/files/common/files';
import { FileService } from 'vs/platform/files/common/fileService';
import { Schemas } from 'vs/base/common/network';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IWorkspaceContextService, toWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { IWorkbenchConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
import { onUnexpectedError } from 'vs/base/common/errors';
import { setFullscreen } from 'vs/base/browser/browser';
import { URI } from 'vs/base/common/uri';
import { IWorkspaceInitializationPayload } from 'vs/platform/workspaces/common/workspaces';
import { encodePath, URI } from 'vs/base/common/uri';
import { isRecentFolder, IWorkspaceInitializationPayload, IWorkspacesService } from 'vs/platform/workspaces/common/workspaces';
import { WorkspaceService } from 'vs/workbench/services/configuration/browser/configurationService';
import { ConfigurationCache } from 'vs/workbench/services/configuration/browser/configurationCache';
import { ISignService } from 'vs/platform/sign/common/sign';
Expand Down Expand Up @@ -68,6 +68,7 @@ import { safeStringify } from 'vs/base/common/objects';
import { ICredentialsService } from 'vs/workbench/services/credentials/common/credentials';
import { IndexedDB } from 'vs/base/browser/indexedDB';
import { CodeServerClientAdditions } from 'vs/workbench/browser/client';
import { BrowserWorkspacesService } from 'vs/workbench/services/workspaces/browser/workspacesService';

class BrowserMain extends Disposable {

Expand Down Expand Up @@ -219,6 +220,63 @@ class BrowserMain extends Disposable {
})
]);

/**
* Added to persist recent workspaces in the browser.
* @author coder
* @example User specified a directory at startup.
* ```sh
* code-server ./path/to/project/
* ```
*
* @example Blank project without CLI arguments,
* using the last opened directory in the browser.
* ```sh
* code-server
* open http://localhost:8000/
* ```
*
* @example Query params override CLI arguments.
* ```sh
* code-server ./path/to/project/
* open http://localhost:8000/?folder=/path/to/different/project
* ```
*/
const browserWorkspacesService = new BrowserWorkspacesService(storageService, configurationService, logService, fileService, environmentService, uriIdentityService);
serviceCollection.set(IWorkspacesService, browserWorkspacesService);
const workspace = configurationService.getWorkspace();

logService.debug('Workspace Folders:', workspace.folders);

if (workspace.folders.length === 0) {
logService.debug('Workspace is empty. Checking for recent folders...');

const recentlyOpened = await browserWorkspacesService.getRecentlyOpened();

for (const recent of recentlyOpened.workspaces) {
if (isRecentFolder(recent)) {
logService.debug('Recent folder found...');
const folder = toWorkspaceFolder(recent.folderUri);
// Note that the `folders` property should be reassigned instead of pushed into.
// This property has a setter which updates the workspace's file cache.
workspace.folders = [folder];


/**
* Opening a folder from the browser navigates to a URL including the folder param.
* However, since we're overriding the default state of a blank editor,
* we update the URL query param to match this behavior.
* This is especially useful when a user wants to share a link to server with a specific folder.
*
* @see `WorkspaceProvider.createTargetUrl`
* @see `WorkspaceProvider.QUERY_PARAM_FOLDER`
*/
const nextQueryParam = `?folder=${encodePath(folder.uri.path)}`;
window.history.replaceState(null, '', nextQueryParam);
break;
}
}
}

// Workspace Trust Service
const workspaceTrustEnablementService = new WorkspaceTrustEnablementService(configurationService, environmentService);
serviceCollection.set(IWorkspaceTrustEnablementService, workspaceTrustEnablementService);
Expand Down