diff --git a/src/browser/pages/home.html b/src/browser/pages/home.html index 139963ad..d2bc92f7 100644 --- a/src/browser/pages/home.html +++ b/src/browser/pages/home.html @@ -30,6 +30,16 @@ +
+
+

Recent

+
Choose a recent directory or workspace to launch below.
+
+
+ {{APP_LIST:RECENT_PROJECTS}} +
+
+

Editors

diff --git a/src/common/api.ts b/src/common/api.ts index 6f6784f9..a338bb3c 100644 --- a/src/common/api.ts +++ b/src/common/api.ts @@ -34,6 +34,7 @@ export interface SessionResponse { export interface RecentResponse { readonly paths: string[] + readonly workspaces: string[] } export interface RunningResponse { diff --git a/src/node/app/api.ts b/src/node/app/api.ts index b5f2e938..f3a86680 100644 --- a/src/node/app/api.ts +++ b/src/node/app/api.ts @@ -28,7 +28,7 @@ interface ServerSession { } interface VsRecents { - [key: string]: (string | object)[] + [key: string]: (string | { configURIPath: string })[] } type VsSettings = [string, string][] @@ -322,28 +322,34 @@ export class ApiHttpProvider extends HttpProvider { throw new Error("settings appear malformed") } - const paths: { [key: string]: Promise } = {} + const pathPromises: { [key: string]: Promise } = {} + const workspacePromises: { [key: string]: Promise } = {} Object.values(JSON.parse(setting[1]) as VsRecents).forEach((recents) => { - recents - .filter((recent) => typeof recent === "string") - .forEach((recent) => { - try { - const pathname = url.parse(recent as string).pathname - if (pathname && !paths[pathname]) { - paths[pathname] = new Promise((resolve) => { - fs.stat(pathname) - .then(() => resolve(pathname)) - .catch(() => resolve()) - }) - } - } catch (error) { - logger.debug("invalid path", field("path", recent)) + recents.forEach((recent) => { + try { + const target = typeof recent === "string" ? pathPromises : workspacePromises + const pathname = url.parse(typeof recent === "string" ? recent : recent.configURIPath).pathname + if (pathname && !target[pathname]) { + target[pathname] = new Promise((resolve) => { + fs.stat(pathname) + .then(() => resolve(pathname)) + .catch(() => resolve()) + }) } - }) + } catch (error) { + logger.debug("invalid path", field("path", recent)) + } + }) }) + const [paths, workspaces] = await Promise.all([ + Promise.all(Object.values(pathPromises)), + Promise.all(Object.values(workspacePromises)), + ]) + return { - paths: await Promise.all(Object.values(paths)), + paths: paths.filter((p) => !!p), + workspaces: workspaces.filter((p) => !!p), } } catch (error) { if (error.code !== "ENOENT") { @@ -351,7 +357,7 @@ export class ApiHttpProvider extends HttpProvider { } } - return { paths: [] } + return { paths: [], workspaces: [] } } /** diff --git a/src/node/app/app.ts b/src/node/app/app.ts index cd211131..8f75cc2b 100644 --- a/src/node/app/app.ts +++ b/src/node/app/app.ts @@ -1,6 +1,6 @@ import * as http from "http" import * as querystring from "querystring" -import { Application } from "../../common/api" +import { Application, RecentResponse } from "../../common/api" import { HttpCode, HttpError } from "../../common/http" import { HttpProvider, HttpProviderOptions, HttpResponse, Route } from "../http" import { ApiHttpProvider } from "./api" @@ -86,6 +86,7 @@ export class MainHttpProvider extends HttpProvider { response.content = response.content .replace(/{{UPDATE:NAME}}/, await this.getUpdate()) .replace(/{{APP_LIST:RUNNING}}/, this.getAppRows(running.applications)) + .replace(/{{APP_LIST:RECENT_PROJECTS}}/, this.getRecentProjectRows(await this.api.recent())) .replace( /{{APP_LIST:EDITORS}}/, this.getAppRows(apps.filter((app) => app.categories && app.categories.includes("Editor"))), @@ -107,6 +108,21 @@ export class MainHttpProvider extends HttpProvider { return undefined } + private getRecentProjectRows(recents: RecentResponse): string { + return recents.paths.length > 0 || recents.workspaces.length > 0 + ? recents.paths.map((recent) => this.getRecentProjectRow(recent)).join("\n") + + recents.workspaces.map((recent) => this.getRecentProjectRow(recent, true)).join("\n") + : `
No recent directories or workspaces.
` + } + + private getRecentProjectRow(recent: string, workspace?: boolean): string { + return `` + } + private getAppRows(apps: ReadonlyArray): string { return apps.length > 0 ? apps.map((app) => this.getAppRow(app)).join("\n")