diff --git a/.gitignore b/.gitignore index 9a164f9..bc80ce5 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,5 @@ .cache-loader dist node_modules -settings.html -welcome.html images/settings gitlens-*.vsix \ No newline at end of file diff --git a/.vscodeignore b/.vscodeignore index 4618c6b..8bf43e2 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -2,7 +2,7 @@ .cache-loader/** .github/** .vscode/** -dist/ui/** +dist/webviews/main.js emoji/** images/docs/** images/**/*.pdn @@ -10,13 +10,15 @@ node_modules/** src/** test/** *.map +.eslintrc.json .gitignore +.mailmap .prettierignore .prettierrc CODE_OF_CONDUCT.md CONTRIBUTING.md +generateEmojiShortcodeMap.js package-lock.json tsconfig.json -tslint.json -ui.tsconfig.json -webpack.config.js \ No newline at end of file +webpack.config.js +webviews.tsconfig.json diff --git a/package-lock.json b/package-lock.json index d666abf..3cbe836 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4964,6 +4964,12 @@ "uglify-js": "3.4.x" } }, + "html-webpack-exclude-assets-plugin": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/html-webpack-exclude-assets-plugin/-/html-webpack-exclude-assets-plugin-0.0.7.tgz", + "integrity": "sha512-gaYKMGBPDts3Fb1WXyDEEcS/0TSRg2IDl3EsbQL2AkKWTqdjSKwfQ8Iz0RhPiWErJfqhq5/wkhoYyjQoG55pug==", + "dev": true + }, "html-webpack-inline-source-plugin": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/html-webpack-inline-source-plugin/-/html-webpack-inline-source-plugin-0.0.10.tgz", diff --git a/package.json b/package.json index 071a6f3..59edc04 100644 --- a/package.json +++ b/package.json @@ -4978,8 +4978,8 @@ "rebuild": "npm run reset && npm run build", "reset": "npm run clean && npm install --no-save", "watch": "webpack --watch --env.development --info-verbosity verbose", - "ui:optimize": "webpack --config-name ui --env.optimizeImages", - "ui:watch": "webpack --watch --config-name ui --env.development --info-verbosity verbose", + "webviews:optimize": "webpack --config-name webviews --env.optimizeImages", + "webviews:watch": "webpack --watch --config-name webviews --env.development --info-verbosity verbose", "update:emoji": "pushd emoji && node ./shortcodeToEmoji.js && popd", "postinstall": "node ./node_modules/vscode/bin/install", "vscode:prepublish": "npm run reset && npm run bundle" @@ -5004,6 +5004,7 @@ "eslint-loader": "2.1.2", "eslint-plugin-import": "2.16.0", "eslint-plugin-prettiest": "0.0.1", + "html-webpack-exclude-assets-plugin": "0.0.7", "html-webpack-inline-source-plugin": "0.0.10", "html-webpack-plugin": "3.2.0", "imagemin-webpack-plugin": "2.4.2", diff --git a/src/annotations/annotations.ts b/src/annotations/annotations.ts index 731bb94..a95bd46 100644 --- a/src/annotations/annotations.ts +++ b/src/annotations/annotations.ts @@ -21,7 +21,7 @@ import { GitUri } from '../git/gitService'; import { Objects, Strings } from '../system'; -import { toRgba } from '../ui/shared/colors'; +import { toRgba } from '../webviews/apps/shared/colors'; export interface ComputedHeatmap { cold: boolean; diff --git a/src/commands/common.ts b/src/commands/common.ts index bdfbe07..14f8b52 100644 --- a/src/commands/common.ts +++ b/src/commands/common.ts @@ -78,6 +78,7 @@ export enum Commands { ShowQuickStashList = 'gitlens.showQuickStashList', ShowRepositoriesView = 'gitlens.showRepositoriesView', ShowSearchView = 'gitlens.showSearchView', + ShowHistoryPage = 'gitlens.showHistoryPage', ShowSettingsPage = 'gitlens.showSettingsPage', ShowWelcomePage = 'gitlens.showWelcomePage', StashApply = 'gitlens.stashApply', diff --git a/src/container.ts b/src/container.ts index 535ec04..9c32608 100644 --- a/src/container.ts +++ b/src/container.ts @@ -21,8 +21,8 @@ import { RepositoriesView } from './views/repositoriesView'; import { SearchView } from './views/searchView'; import { ViewCommands } from './views/viewCommands'; import { VslsController } from './vsls/vsls'; -import { SettingsEditor } from './webviews/settingsEditor'; -import { WelcomeEditor } from './webviews/welcomeEditor'; +import { SettingsWebview } from './webviews/settingsWebview'; +import { WelcomeWebview } from './webviews/welcomeWebview'; export class Container { private static _configsAffectedByMode: string[] | undefined; @@ -49,8 +49,8 @@ export class Container { context.subscriptions.push((this._statusBarController = new StatusBarController())); context.subscriptions.push((this._codeLensController = new GitCodeLensController())); context.subscriptions.push((this._keyboard = new Keyboard())); - context.subscriptions.push((this._settingsEditor = new SettingsEditor())); - context.subscriptions.push((this._welcomeEditor = new WelcomeEditor())); + context.subscriptions.push((this._settingsWebview = new SettingsWebview())); + context.subscriptions.push((this._welcomeWebview = new WelcomeWebview())); if (config.views.compare.enabled) { context.subscriptions.push((this._compareView = new CompareView())); @@ -238,9 +238,9 @@ export class Container { return this._searchView; } - private static _settingsEditor: SettingsEditor; - static get settingsEditor() { - return this._settingsEditor; + private static _settingsWebview: SettingsWebview; + static get settingsWebview() { + return this._settingsWebview; } private static _statusBarController: StatusBarController; @@ -266,9 +266,9 @@ export class Container { return this._vsls; } - private static _welcomeEditor: WelcomeEditor; - static get welcomeEditor() { - return this._welcomeEditor; + private static _welcomeWebview: WelcomeWebview; + static get welcomeWebview() { + return this._welcomeWebview; } private static applyMode(config: Config) { diff --git a/src/ui/ipc.ts b/src/ui/ipc.ts deleted file mode 100644 index be715fc..0000000 --- a/src/ui/ipc.ts +++ /dev/null @@ -1,30 +0,0 @@ -'use strict'; -import { Config } from '../config'; - -export interface Bootstrap { - config: Config; -} - -export interface SettingsBootstrap extends Bootstrap { - scope: 'user' | 'workspace'; - scopes: ['user' | 'workspace', string][]; -} - -export interface WelcomeBootstrap extends Bootstrap {} - -export interface SaveSettingsMessage { - type: 'saveSettings'; - changes: { - [key: string]: any; - }; - removes: string[]; - scope: 'user' | 'workspace'; - uri?: string; -} - -export interface SettingsChangedMessage { - type: 'settingsChanged'; - config: Config; -} - -export type Message = SaveSettingsMessage | SettingsChangedMessage; diff --git a/src/ui/settings/index.ts b/src/ui/settings/index.ts deleted file mode 100644 index 1944b08..0000000 --- a/src/ui/settings/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -'use strict'; -import { SettingsApp } from './app'; - -new SettingsApp(); diff --git a/src/ui/welcome/app.ts b/src/ui/welcome/app.ts deleted file mode 100644 index 87db0f2..0000000 --- a/src/ui/welcome/app.ts +++ /dev/null @@ -1,39 +0,0 @@ -'use strict'; -/*global window*/ -import { WelcomeBootstrap } from '../ipc'; -import { App } from '../shared/app-base'; -import { DOM } from '../shared/dom'; - -const bootstrap: WelcomeBootstrap = (window as any).bootstrap; - -export class WelcomeApp extends App { - private _commandRelay: HTMLAnchorElement | null | undefined; - - constructor() { - super('WelcomeApp', bootstrap); - } - - protected onInitialize() { - this._commandRelay = DOM.getElementById('commandRelay'); - } - - protected onBind() { - const onClicked = this.onClicked.bind(this); - DOM.listenAll('button[data-href]', 'click', function(this: HTMLButtonElement) { - onClicked(this); - }); - } - - private onClicked(element: HTMLButtonElement) { - this.executeCommand(element.dataset.href); - } - - private executeCommand(command: string | undefined) { - if (command === undefined || this._commandRelay == null) return; - - this.log(`${this.appName}.executeCommand: command=${command}`); - - this._commandRelay.setAttribute('href', command); - this._commandRelay.click(); - } -} diff --git a/src/ui/welcome/index.ts b/src/ui/welcome/index.ts deleted file mode 100644 index 6b79756..0000000 --- a/src/ui/welcome/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -'use strict'; -import { WelcomeApp } from './app'; -// import { Snow } from './snow'; - -new WelcomeApp(); -// requestAnimationFrame(() => new Snow()); diff --git a/src/ui/images/settings/blame-avatars-compact.png b/src/webviews/apps/images/settings/blame-avatars-compact.png similarity index 100% rename from src/ui/images/settings/blame-avatars-compact.png rename to src/webviews/apps/images/settings/blame-avatars-compact.png diff --git a/src/ui/images/settings/blame-avatars.png b/src/webviews/apps/images/settings/blame-avatars.png similarity index 100% rename from src/ui/images/settings/blame-avatars.png rename to src/webviews/apps/images/settings/blame-avatars.png diff --git a/src/ui/images/settings/blame-compact.png b/src/webviews/apps/images/settings/blame-compact.png similarity index 100% rename from src/ui/images/settings/blame-compact.png rename to src/webviews/apps/images/settings/blame-compact.png diff --git a/src/ui/images/settings/blame-heatmap-left.png b/src/webviews/apps/images/settings/blame-heatmap-left.png similarity index 100% rename from src/ui/images/settings/blame-heatmap-left.png rename to src/webviews/apps/images/settings/blame-heatmap-left.png diff --git a/src/ui/images/settings/blame-heatmap-right.png b/src/webviews/apps/images/settings/blame-heatmap-right.png similarity index 100% rename from src/ui/images/settings/blame-heatmap-right.png rename to src/webviews/apps/images/settings/blame-heatmap-right.png diff --git a/src/ui/images/settings/blame-highlight-gutter.png b/src/webviews/apps/images/settings/blame-highlight-gutter.png similarity index 100% rename from src/ui/images/settings/blame-highlight-gutter.png rename to src/webviews/apps/images/settings/blame-highlight-gutter.png diff --git a/src/ui/images/settings/blame-highlight-line.png b/src/webviews/apps/images/settings/blame-highlight-line.png similarity index 100% rename from src/ui/images/settings/blame-highlight-line.png rename to src/webviews/apps/images/settings/blame-highlight-line.png diff --git a/src/ui/images/settings/blame-highlight-scrollbar.png b/src/webviews/apps/images/settings/blame-highlight-scrollbar.png similarity index 100% rename from src/ui/images/settings/blame-highlight-scrollbar.png rename to src/webviews/apps/images/settings/blame-highlight-scrollbar.png diff --git a/src/ui/images/settings/blame.png b/src/webviews/apps/images/settings/blame.png similarity index 100% rename from src/ui/images/settings/blame.png rename to src/webviews/apps/images/settings/blame.png diff --git a/src/ui/images/settings/code-lens-blocks-authors.png b/src/webviews/apps/images/settings/code-lens-blocks-authors.png similarity index 100% rename from src/ui/images/settings/code-lens-blocks-authors.png rename to src/webviews/apps/images/settings/code-lens-blocks-authors.png diff --git a/src/ui/images/settings/code-lens-blocks-recent+authors.png b/src/webviews/apps/images/settings/code-lens-blocks-recent+authors.png similarity index 100% rename from src/ui/images/settings/code-lens-blocks-recent+authors.png rename to src/webviews/apps/images/settings/code-lens-blocks-recent+authors.png diff --git a/src/ui/images/settings/code-lens-blocks-recent.png b/src/webviews/apps/images/settings/code-lens-blocks-recent.png similarity index 100% rename from src/ui/images/settings/code-lens-blocks-recent.png rename to src/webviews/apps/images/settings/code-lens-blocks-recent.png diff --git a/src/ui/images/settings/code-lens-containers-authors.png b/src/webviews/apps/images/settings/code-lens-containers-authors.png similarity index 100% rename from src/ui/images/settings/code-lens-containers-authors.png rename to src/webviews/apps/images/settings/code-lens-containers-authors.png diff --git a/src/ui/images/settings/code-lens-containers-recent+authors.png b/src/webviews/apps/images/settings/code-lens-containers-recent+authors.png similarity index 100% rename from src/ui/images/settings/code-lens-containers-recent+authors.png rename to src/webviews/apps/images/settings/code-lens-containers-recent+authors.png diff --git a/src/ui/images/settings/code-lens-containers-recent.png b/src/webviews/apps/images/settings/code-lens-containers-recent.png similarity index 100% rename from src/ui/images/settings/code-lens-containers-recent.png rename to src/webviews/apps/images/settings/code-lens-containers-recent.png diff --git a/src/ui/images/settings/code-lens-file-authors.png b/src/webviews/apps/images/settings/code-lens-file-authors.png similarity index 100% rename from src/ui/images/settings/code-lens-file-authors.png rename to src/webviews/apps/images/settings/code-lens-file-authors.png diff --git a/src/ui/images/settings/code-lens-file-recent+authors.png b/src/webviews/apps/images/settings/code-lens-file-recent+authors.png similarity index 100% rename from src/ui/images/settings/code-lens-file-recent+authors.png rename to src/webviews/apps/images/settings/code-lens-file-recent+authors.png diff --git a/src/ui/images/settings/code-lens-file-recent.png b/src/webviews/apps/images/settings/code-lens-file-recent.png similarity index 100% rename from src/ui/images/settings/code-lens-file-recent.png rename to src/webviews/apps/images/settings/code-lens-file-recent.png diff --git a/src/ui/images/settings/code-lens.png b/src/webviews/apps/images/settings/code-lens.png similarity index 100% rename from src/ui/images/settings/code-lens.png rename to src/webviews/apps/images/settings/code-lens.png diff --git a/src/ui/images/settings/current-line-blame-on-scrollable.png b/src/webviews/apps/images/settings/current-line-blame-on-scrollable.png similarity index 100% rename from src/ui/images/settings/current-line-blame-on-scrollable.png rename to src/webviews/apps/images/settings/current-line-blame-on-scrollable.png diff --git a/src/ui/images/settings/current-line-blame-on.png b/src/webviews/apps/images/settings/current-line-blame-on.png similarity index 100% rename from src/ui/images/settings/current-line-blame-on.png rename to src/webviews/apps/images/settings/current-line-blame-on.png diff --git a/src/ui/images/settings/current-line-blame.png b/src/webviews/apps/images/settings/current-line-blame.png similarity index 100% rename from src/ui/images/settings/current-line-blame.png rename to src/webviews/apps/images/settings/current-line-blame.png diff --git a/src/ui/images/settings/heatmap.png b/src/webviews/apps/images/settings/heatmap.png similarity index 100% rename from src/ui/images/settings/heatmap.png rename to src/webviews/apps/images/settings/heatmap.png diff --git a/src/ui/images/settings/hovers-annotations-changes.png b/src/webviews/apps/images/settings/hovers-annotations-changes.png similarity index 100% rename from src/ui/images/settings/hovers-annotations-changes.png rename to src/webviews/apps/images/settings/hovers-annotations-changes.png diff --git a/src/ui/images/settings/hovers-annotations-compact.png b/src/webviews/apps/images/settings/hovers-annotations-compact.png similarity index 100% rename from src/ui/images/settings/hovers-annotations-compact.png rename to src/webviews/apps/images/settings/hovers-annotations-compact.png diff --git a/src/ui/images/settings/hovers-annotations-details+changes-avatars.png b/src/webviews/apps/images/settings/hovers-annotations-details+changes-avatars.png similarity index 100% rename from src/ui/images/settings/hovers-annotations-details+changes-avatars.png rename to src/webviews/apps/images/settings/hovers-annotations-details+changes-avatars.png diff --git a/src/ui/images/settings/hovers-annotations-details+changes.png b/src/webviews/apps/images/settings/hovers-annotations-details+changes.png similarity index 100% rename from src/ui/images/settings/hovers-annotations-details+changes.png rename to src/webviews/apps/images/settings/hovers-annotations-details+changes.png diff --git a/src/ui/images/settings/hovers-annotations-details-avatars.png b/src/webviews/apps/images/settings/hovers-annotations-details-avatars.png similarity index 100% rename from src/ui/images/settings/hovers-annotations-details-avatars.png rename to src/webviews/apps/images/settings/hovers-annotations-details-avatars.png diff --git a/src/ui/images/settings/hovers-annotations-details.png b/src/webviews/apps/images/settings/hovers-annotations-details.png similarity index 100% rename from src/ui/images/settings/hovers-annotations-details.png rename to src/webviews/apps/images/settings/hovers-annotations-details.png diff --git a/src/ui/images/settings/hovers-annotations-heatmap.png b/src/webviews/apps/images/settings/hovers-annotations-heatmap.png similarity index 100% rename from src/ui/images/settings/hovers-annotations-heatmap.png rename to src/webviews/apps/images/settings/hovers-annotations-heatmap.png diff --git a/src/ui/images/settings/hovers-annotations.png b/src/webviews/apps/images/settings/hovers-annotations.png similarity index 100% rename from src/ui/images/settings/hovers-annotations.png rename to src/webviews/apps/images/settings/hovers-annotations.png diff --git a/src/ui/images/settings/hovers-currentLine-annotation-changes.png b/src/webviews/apps/images/settings/hovers-currentLine-annotation-changes.png similarity index 100% rename from src/ui/images/settings/hovers-currentLine-annotation-changes.png rename to src/webviews/apps/images/settings/hovers-currentLine-annotation-changes.png diff --git a/src/ui/images/settings/hovers-currentLine-annotation-details+changes-avatars.png b/src/webviews/apps/images/settings/hovers-currentLine-annotation-details+changes-avatars.png similarity index 100% rename from src/ui/images/settings/hovers-currentLine-annotation-details+changes-avatars.png rename to src/webviews/apps/images/settings/hovers-currentLine-annotation-details+changes-avatars.png diff --git a/src/ui/images/settings/hovers-currentLine-annotation-details+changes.png b/src/webviews/apps/images/settings/hovers-currentLine-annotation-details+changes.png similarity index 100% rename from src/ui/images/settings/hovers-currentLine-annotation-details+changes.png rename to src/webviews/apps/images/settings/hovers-currentLine-annotation-details+changes.png diff --git a/src/ui/images/settings/hovers-currentLine-annotation-details-avatars.png b/src/webviews/apps/images/settings/hovers-currentLine-annotation-details-avatars.png similarity index 100% rename from src/ui/images/settings/hovers-currentLine-annotation-details-avatars.png rename to src/webviews/apps/images/settings/hovers-currentLine-annotation-details-avatars.png diff --git a/src/ui/images/settings/hovers-currentLine-annotation-details.png b/src/webviews/apps/images/settings/hovers-currentLine-annotation-details.png similarity index 100% rename from src/ui/images/settings/hovers-currentLine-annotation-details.png rename to src/webviews/apps/images/settings/hovers-currentLine-annotation-details.png diff --git a/src/ui/images/settings/hovers-currentLine-annotation.png b/src/webviews/apps/images/settings/hovers-currentLine-annotation.png similarity index 100% rename from src/ui/images/settings/hovers-currentLine-annotation.png rename to src/webviews/apps/images/settings/hovers-currentLine-annotation.png diff --git a/src/ui/images/settings/hovers-currentLine-line-blame.png b/src/webviews/apps/images/settings/hovers-currentLine-line-blame.png similarity index 100% rename from src/ui/images/settings/hovers-currentLine-line-blame.png rename to src/webviews/apps/images/settings/hovers-currentLine-line-blame.png diff --git a/src/ui/images/settings/hovers-currentLine-line-changes.png b/src/webviews/apps/images/settings/hovers-currentLine-line-changes.png similarity index 100% rename from src/ui/images/settings/hovers-currentLine-line-changes.png rename to src/webviews/apps/images/settings/hovers-currentLine-line-changes.png diff --git a/src/ui/images/settings/hovers-currentLine-line-details+changes-avatars.png b/src/webviews/apps/images/settings/hovers-currentLine-line-details+changes-avatars.png similarity index 100% rename from src/ui/images/settings/hovers-currentLine-line-details+changes-avatars.png rename to src/webviews/apps/images/settings/hovers-currentLine-line-details+changes-avatars.png diff --git a/src/ui/images/settings/hovers-currentLine-line-details+changes.png b/src/webviews/apps/images/settings/hovers-currentLine-line-details+changes.png similarity index 100% rename from src/ui/images/settings/hovers-currentLine-line-details+changes.png rename to src/webviews/apps/images/settings/hovers-currentLine-line-details+changes.png diff --git a/src/ui/images/settings/hovers-currentLine-line-details-avatars.png b/src/webviews/apps/images/settings/hovers-currentLine-line-details-avatars.png similarity index 100% rename from src/ui/images/settings/hovers-currentLine-line-details-avatars.png rename to src/webviews/apps/images/settings/hovers-currentLine-line-details-avatars.png diff --git a/src/ui/images/settings/hovers-currentLine-line-details.png b/src/webviews/apps/images/settings/hovers-currentLine-line-details.png similarity index 100% rename from src/ui/images/settings/hovers-currentLine-line-details.png rename to src/webviews/apps/images/settings/hovers-currentLine-line-details.png diff --git a/src/ui/images/settings/hovers-currentLine-line.png b/src/webviews/apps/images/settings/hovers-currentLine-line.png similarity index 100% rename from src/ui/images/settings/hovers-currentLine-line.png rename to src/webviews/apps/images/settings/hovers-currentLine-line.png diff --git a/src/ui/images/settings/modes-status-bar-left.png b/src/webviews/apps/images/settings/modes-status-bar-left.png similarity index 100% rename from src/ui/images/settings/modes-status-bar-left.png rename to src/webviews/apps/images/settings/modes-status-bar-left.png diff --git a/src/ui/images/settings/modes-status-bar-right.png b/src/webviews/apps/images/settings/modes-status-bar-right.png similarity index 100% rename from src/ui/images/settings/modes-status-bar-right.png rename to src/webviews/apps/images/settings/modes-status-bar-right.png diff --git a/src/ui/images/settings/recent-changes-highlight-gutter.png b/src/webviews/apps/images/settings/recent-changes-highlight-gutter.png similarity index 100% rename from src/ui/images/settings/recent-changes-highlight-gutter.png rename to src/webviews/apps/images/settings/recent-changes-highlight-gutter.png diff --git a/src/ui/images/settings/recent-changes-highlight-line.png b/src/webviews/apps/images/settings/recent-changes-highlight-line.png similarity index 100% rename from src/ui/images/settings/recent-changes-highlight-line.png rename to src/webviews/apps/images/settings/recent-changes-highlight-line.png diff --git a/src/ui/images/settings/recent-changes-highlight-scrollbar.png b/src/webviews/apps/images/settings/recent-changes-highlight-scrollbar.png similarity index 100% rename from src/ui/images/settings/recent-changes-highlight-scrollbar.png rename to src/webviews/apps/images/settings/recent-changes-highlight-scrollbar.png diff --git a/src/ui/images/settings/recent-changes.png b/src/webviews/apps/images/settings/recent-changes.png similarity index 100% rename from src/ui/images/settings/recent-changes.png rename to src/webviews/apps/images/settings/recent-changes.png diff --git a/src/ui/images/settings/status-bar-left.png b/src/webviews/apps/images/settings/status-bar-left.png similarity index 100% rename from src/ui/images/settings/status-bar-left.png rename to src/webviews/apps/images/settings/status-bar-left.png diff --git a/src/ui/images/settings/status-bar-right.png b/src/webviews/apps/images/settings/status-bar-right.png similarity index 100% rename from src/ui/images/settings/status-bar-right.png rename to src/webviews/apps/images/settings/status-bar-right.png diff --git a/src/ui/images/settings/status-bar.png b/src/webviews/apps/images/settings/status-bar.png similarity index 100% rename from src/ui/images/settings/status-bar.png rename to src/webviews/apps/images/settings/status-bar.png diff --git a/src/ui/images/settings/view-compare-avatars.png b/src/webviews/apps/images/settings/view-compare-avatars.png similarity index 100% rename from src/ui/images/settings/view-compare-avatars.png rename to src/webviews/apps/images/settings/view-compare-avatars.png diff --git a/src/ui/images/settings/view-compare-tree-compact.png b/src/webviews/apps/images/settings/view-compare-tree-compact.png similarity index 100% rename from src/ui/images/settings/view-compare-tree-compact.png rename to src/webviews/apps/images/settings/view-compare-tree-compact.png diff --git a/src/ui/images/settings/view-compare-tree.png b/src/webviews/apps/images/settings/view-compare-tree.png similarity index 100% rename from src/ui/images/settings/view-compare-tree.png rename to src/webviews/apps/images/settings/view-compare-tree.png diff --git a/src/ui/images/settings/view-compare.png b/src/webviews/apps/images/settings/view-compare.png similarity index 100% rename from src/ui/images/settings/view-compare.png rename to src/webviews/apps/images/settings/view-compare.png diff --git a/src/ui/images/settings/view-file-history-avatars.png b/src/webviews/apps/images/settings/view-file-history-avatars.png similarity index 100% rename from src/ui/images/settings/view-file-history-avatars.png rename to src/webviews/apps/images/settings/view-file-history-avatars.png diff --git a/src/ui/images/settings/view-file-history.png b/src/webviews/apps/images/settings/view-file-history.png similarity index 100% rename from src/ui/images/settings/view-file-history.png rename to src/webviews/apps/images/settings/view-file-history.png diff --git a/src/ui/images/settings/view-line-history-avatars.png b/src/webviews/apps/images/settings/view-line-history-avatars.png similarity index 100% rename from src/ui/images/settings/view-line-history-avatars.png rename to src/webviews/apps/images/settings/view-line-history-avatars.png diff --git a/src/ui/images/settings/view-line-history.png b/src/webviews/apps/images/settings/view-line-history.png similarity index 100% rename from src/ui/images/settings/view-line-history.png rename to src/webviews/apps/images/settings/view-line-history.png diff --git a/src/ui/images/settings/view-repositories-avatars.png b/src/webviews/apps/images/settings/view-repositories-avatars.png similarity index 100% rename from src/ui/images/settings/view-repositories-avatars.png rename to src/webviews/apps/images/settings/view-repositories-avatars.png diff --git a/src/ui/images/settings/view-repositories-tree-compact.png b/src/webviews/apps/images/settings/view-repositories-tree-compact.png similarity index 100% rename from src/ui/images/settings/view-repositories-tree-compact.png rename to src/webviews/apps/images/settings/view-repositories-tree-compact.png diff --git a/src/ui/images/settings/view-repositories-tree.png b/src/webviews/apps/images/settings/view-repositories-tree.png similarity index 100% rename from src/ui/images/settings/view-repositories-tree.png rename to src/webviews/apps/images/settings/view-repositories-tree.png diff --git a/src/ui/images/settings/view-repositories.png b/src/webviews/apps/images/settings/view-repositories.png similarity index 100% rename from src/ui/images/settings/view-repositories.png rename to src/webviews/apps/images/settings/view-repositories.png diff --git a/src/ui/images/settings/view-search-avatars.png b/src/webviews/apps/images/settings/view-search-avatars.png similarity index 100% rename from src/ui/images/settings/view-search-avatars.png rename to src/webviews/apps/images/settings/view-search-avatars.png diff --git a/src/ui/images/settings/view-search-tree-compact.png b/src/webviews/apps/images/settings/view-search-tree-compact.png similarity index 100% rename from src/ui/images/settings/view-search-tree-compact.png rename to src/webviews/apps/images/settings/view-search-tree-compact.png diff --git a/src/ui/images/settings/view-search-tree.png b/src/webviews/apps/images/settings/view-search-tree.png similarity index 100% rename from src/ui/images/settings/view-search-tree.png rename to src/webviews/apps/images/settings/view-search-tree.png diff --git a/src/ui/images/settings/view-search.png b/src/webviews/apps/images/settings/view-search.png similarity index 100% rename from src/ui/images/settings/view-search.png rename to src/webviews/apps/images/settings/view-search.png diff --git a/src/ui/scss/main.scss b/src/webviews/apps/scss/main.scss similarity index 100% rename from src/ui/scss/main.scss rename to src/webviews/apps/scss/main.scss diff --git a/src/ui/scss/popup.scss b/src/webviews/apps/scss/popup.scss similarity index 100% rename from src/ui/scss/popup.scss rename to src/webviews/apps/scss/popup.scss diff --git a/src/ui/settings/index.html b/src/webviews/apps/settings/index.html similarity index 100% rename from src/ui/settings/index.html rename to src/webviews/apps/settings/index.html diff --git a/src/ui/settings/app.ts b/src/webviews/apps/settings/index.ts similarity index 91% rename from src/ui/settings/app.ts rename to src/webviews/apps/settings/index.ts index 2e77d35..70485ae 100644 --- a/src/ui/settings/app.ts +++ b/src/webviews/apps/settings/index.ts @@ -1,12 +1,12 @@ 'use strict'; /*global window document*/ -import { SettingsBootstrap } from '../ipc'; -import { App } from '../shared/app-base'; +import { SettingsBootstrap } from '../../protocol'; +import { AppWithConfig } from '../shared/appWithConfigBase'; import { DOM } from '../shared/dom'; const bootstrap: SettingsBootstrap = (window as any).bootstrap; -export class SettingsApp extends App { +export class SettingsApp extends AppWithConfig { private _scopes: HTMLSelectElement | null = null; constructor() { @@ -32,8 +32,8 @@ export class SettingsApp extends App { } } - protected onBind() { - const me = this; + protected onBind(me: this) { + super.onBind(me); DOM.listenAll('.section__header', 'click', function(this: HTMLInputElement, e: Event) { return me.onSectionHeaderClicked(this, e as MouseEvent); @@ -91,3 +91,5 @@ export class SettingsApp extends App { element.classList.toggle('collapsed'); } } + +new SettingsApp(); diff --git a/src/webviews/apps/shared/appBase.ts b/src/webviews/apps/shared/appBase.ts new file mode 100644 index 0000000..c637a39 --- /dev/null +++ b/src/webviews/apps/shared/appBase.ts @@ -0,0 +1,74 @@ +'use strict'; +/*global window document*/ +import { AppBootstrap, IpcCommandParamsOf, IpcCommandType, IpcMessage } from '../../protocol'; +import { initializeAndWatchThemeColors } from './theme'; + +interface VsCodeApi { + postMessage(msg: {}): void; + setState(state: {}): void; + getState(): {}; +} + +declare function acquireVsCodeApi(): VsCodeApi; + +let ipcSequence = 0; + +export abstract class App { + private readonly _api: VsCodeApi; + + constructor(protected readonly appName: string, protected readonly bootstrap: TBootstrap) { + this.log(`${this.appName}.ctor`); + + this._api = acquireVsCodeApi(); + initializeAndWatchThemeColors(); + + this.log(`${this.appName}.initializing`); + + this.onInitialize(); + this.onBind(this); + + window.addEventListener('message', this.onMessageReceived.bind(this)); + + this.onInitialized(); + + setTimeout(() => { + document.body.classList.remove('preload'); + }, 500); + } + + protected onInitialize() { + // virtual + } + protected onInitialized() { + // virtual + } + protected onBind(me: this) { + // virtual + } + protected onMessageReceived(e: MessageEvent) { + // virtual + } + + protected log(message: string) { + console.log(message); + } + + protected sendCommand(type: CT, params: IpcCommandParamsOf): void { + return this.postMessage({ id: this.nextIpcId(), method: type.method, params: params }); + } + + private nextIpcId() { + if (ipcSequence === Number.MAX_SAFE_INTEGER) { + ipcSequence = 1; + } + else { + ipcSequence++; + } + + return `webview:${ipcSequence}`; + } + + private postMessage(e: IpcMessage) { + this._api.postMessage(e); + } +} diff --git a/src/ui/shared/app-base.ts b/src/webviews/apps/shared/appWithConfigBase.ts similarity index 71% rename from src/ui/shared/app-base.ts rename to src/webviews/apps/shared/appWithConfigBase.ts index 527c44c..789d301 100644 --- a/src/ui/shared/app-base.ts +++ b/src/webviews/apps/shared/appWithConfigBase.ts @@ -1,44 +1,72 @@ 'use strict'; -/*global window document MutationObserver*/ -import { darken, lighten, opacity } from '../shared/colors'; -import { Bootstrap, Message, SaveSettingsMessage } from '../ipc'; -import { DOM } from '../shared/dom'; - -interface VsCodeApi { - postMessage(msg: {}): void; - setState(state: {}): void; - getState(): {}; -} - -declare function acquireVsCodeApi(): VsCodeApi; - -export abstract class App { - private readonly _api: VsCodeApi; +/*global window document*/ +import { + AppWithConfigBootstrap, + DidChangeConfigurationNotificationType, + IpcMessage, + onIpcNotification, + UpdateConfigurationCommandType +} from '../../protocol'; +import { DOM } from './dom'; +import { App } from './appBase'; + +export abstract class AppWithConfig extends App { private _changes: { [key: string]: any } = Object.create(null); + private _updating: boolean = false; - constructor(protected readonly appName: string, protected readonly bootstrap: TBootstrap) { - this.log(`${this.appName}.ctor`); + constructor(appName: string, bootstrap: TBootstrap) { + super(appName, bootstrap); + } + + protected onInitialized() { + this.setState(); + } + + protected onBind(me: this) { + DOM.listenAll('input[type=checkbox].setting', 'change', function(this: HTMLInputElement) { + return me.onInputChecked(this); + }); + DOM.listenAll('input[type=text].setting, input:not([type]).setting', 'blur', function(this: HTMLInputElement) { + return me.onInputBlurred(this); + }); + DOM.listenAll('input[type=text].setting, input:not([type]).setting', 'focus', function(this: HTMLInputElement) { + return me.onInputFocused(this); + }); + DOM.listenAll('select.setting', 'change', function(this: HTMLSelectElement) { + return me.onInputSelected(this); + }); + DOM.listenAll('[data-token]', 'mousedown', function(this: HTMLElement, e: Event) { + return me.onTokenMouseDown(this, e as MouseEvent); + }); + DOM.listenAll('.popup', 'mousedown', function(this: HTMLElement, e: Event) { + return me.onPopupMouseDown(this, e as MouseEvent); + }); + DOM.listenAll('a.jump-to[href^="#"]', 'click', function(this: HTMLAnchorElement, e: Event) { + return me.onJumpToLinkClicked(this, e as MouseEvent); + }); + } - this._api = acquireVsCodeApi(); + protected onMessageReceived(e: MessageEvent) { + const msg = e.data as IpcMessage; - this.initializeColorPalette(); - this.initialize(); - this.bind(); + switch (msg.method) { + case DidChangeConfigurationNotificationType.method: + onIpcNotification(DidChangeConfigurationNotificationType, msg, params => { + this.bootstrap.config = params.config; - setTimeout(() => { - document.body.classList.remove('preload'); - }, 500); + this.setState(); + }); + break; + } } protected applyChanges() { - const msg: SaveSettingsMessage = { - type: 'saveSettings', + this.sendCommand(UpdateConfigurationCommandType, { changes: { ...this._changes }, removes: Object.keys(this._changes).filter(k => this._changes[k] === undefined), scope: this.getSettingsScope() - }; - this.postMessage(msg); + }); this._changes = Object.create(null); } @@ -47,17 +75,6 @@ export abstract class App { return 'user'; } - protected log(message: string) { - console.log(message); - } - - protected onBind() { - // virtual - } - protected onInitialize() { - // virtual - } - protected onInputBlurred(element: HTMLInputElement) { this.log(`${this.appName}.onInputBlurred: name=${element.name}, value=${element.value}`); @@ -184,17 +201,6 @@ export abstract class App { e.preventDefault(); } - protected onMessageReceived(e: MessageEvent) { - const msg = e.data as Message; - switch (msg.type) { - case 'settingsChanged': - this.bootstrap.config = msg.config; - - this.setState(); - break; - } - } - protected onPopupMouseDown(element: HTMLElement, e: MouseEvent) { // e.stopPropagation(); // e.stopImmediatePropagation(); @@ -219,40 +225,6 @@ export abstract class App { e.preventDefault(); } - protected postMessage(e: Message) { - this._api.postMessage(e); - } - - private bind() { - this.onBind(); - - window.addEventListener('message', this.onMessageReceived.bind(this)); - - const me = this; - - DOM.listenAll('input[type=checkbox].setting', 'change', function(this: HTMLInputElement) { - return me.onInputChecked(this); - }); - DOM.listenAll('input[type=text].setting, input:not([type]).setting', 'blur', function(this: HTMLInputElement) { - return me.onInputBlurred(this); - }); - DOM.listenAll('input[type=text].setting, input:not([type]).setting', 'focus', function(this: HTMLInputElement) { - return me.onInputFocused(this); - }); - DOM.listenAll('select.setting', 'change', function(this: HTMLSelectElement) { - return me.onInputSelected(this); - }); - DOM.listenAll('[data-token]', 'mousedown', function(this: HTMLElement, e: Event) { - return me.onTokenMouseDown(this, e as MouseEvent); - }); - DOM.listenAll('.popup', 'mousedown', function(this: HTMLElement, e: Event) { - return me.onPopupMouseDown(this, e as MouseEvent); - }); - DOM.listenAll('a.jump-to[href^="#"]', 'click', function(this: HTMLAnchorElement, e: Event) { - return me.onJumpToLinkClicked(this, e as MouseEvent); - }); - } - private evaluateStateExpression(expression: string, changes: { [key: string]: string | boolean }): boolean { let state = false; for (const expr of expression.trim().split('&')) { @@ -296,84 +268,6 @@ export abstract class App { return get(this.bootstrap.config, path); } - private initialize() { - this.log(`${this.appName}.initialize`); - - this.onInitialize(); - - this.setState(); - } - - private initializeColorPalette() { - const onColorThemeChanged = () => { - const body = document.body; - const computedStyle = window.getComputedStyle(body); - - const bodyStyle = body.style; - - const font = computedStyle.getPropertyValue('--vscode-font-family').trim(); - if (font) { - bodyStyle.setProperty('--font-family', font); - bodyStyle.setProperty('--font-size', computedStyle.getPropertyValue('--vscode-font-size').trim()); - bodyStyle.setProperty('--font-weight', computedStyle.getPropertyValue('--vscode-font-weight').trim()); - } - else { - bodyStyle.setProperty( - '--font-family', - computedStyle.getPropertyValue('--vscode-editor-font-family').trim() - ); - bodyStyle.setProperty( - '--font-size', - computedStyle.getPropertyValue('--vscode-editor-font-size').trim() - ); - bodyStyle.setProperty( - '--font-weight', - computedStyle.getPropertyValue('--vscode-editor-font-weight').trim() - ); - } - - let color = computedStyle.getPropertyValue('--vscode-editor-background').trim(); - bodyStyle.setProperty('--color-background', color); - bodyStyle.setProperty('--color-background--lighten-05', lighten(color, 5)); - bodyStyle.setProperty('--color-background--darken-05', darken(color, 5)); - bodyStyle.setProperty('--color-background--lighten-075', lighten(color, 7.5)); - bodyStyle.setProperty('--color-background--darken-075', darken(color, 7.5)); - bodyStyle.setProperty('--color-background--lighten-15', lighten(color, 15)); - bodyStyle.setProperty('--color-background--darken-15', darken(color, 15)); - bodyStyle.setProperty('--color-background--lighten-30', lighten(color, 30)); - bodyStyle.setProperty('--color-background--darken-30', darken(color, 30)); - - color = computedStyle.getPropertyValue('--vscode-button-background').trim(); - bodyStyle.setProperty('--color-button-background', color); - bodyStyle.setProperty('--color-button-background--darken-30', darken(color, 30)); - - color = computedStyle.getPropertyValue('--vscode-button-foreground').trim(); - bodyStyle.setProperty('--color-button-foreground', color); - - color = computedStyle.getPropertyValue('--vscode-editor-foreground').trim(); - if (!color) { - color = computedStyle.getPropertyValue('--vscode-foreground').trim(); - } - bodyStyle.setProperty('--color-foreground', color); - bodyStyle.setProperty('--color-foreground--85', opacity(color, 85)); - bodyStyle.setProperty('--color-foreground--75', opacity(color, 75)); - bodyStyle.setProperty('--color-foreground--50', opacity(color, 50)); - - color = computedStyle.getPropertyValue('--vscode-focusBorder').trim(); - bodyStyle.setProperty('--color-focus-border', color); - - color = computedStyle.getPropertyValue('--vscode-textLink-foreground').trim(); - bodyStyle.setProperty('--color-link-foreground', color); - bodyStyle.setProperty('--color-link-foreground--darken-20', darken(color, 20)); - }; - - const observer = new MutationObserver(onColorThemeChanged); - observer.observe(document.body, { attributes: true, attributeFilter: ['class'] }); - - onColorThemeChanged(); - return observer; - } - private setState() { this._updating = true; diff --git a/src/ui/shared/colors.ts b/src/webviews/apps/shared/colors.ts similarity index 100% rename from src/ui/shared/colors.ts rename to src/webviews/apps/shared/colors.ts diff --git a/src/ui/shared/dom.ts b/src/webviews/apps/shared/dom.ts similarity index 100% rename from src/ui/shared/dom.ts rename to src/webviews/apps/shared/dom.ts diff --git a/src/webviews/apps/shared/theme.ts b/src/webviews/apps/shared/theme.ts new file mode 100644 index 0000000..41117a8 --- /dev/null +++ b/src/webviews/apps/shared/theme.ts @@ -0,0 +1,70 @@ +'use strict'; +/*global window document MutationObserver*/ +import { darken, lighten, opacity } from './colors'; + +export function initializeAndWatchThemeColors() { + const onColorThemeChanged = () => { + const body = document.body; + const computedStyle = window.getComputedStyle(body); + + const bodyStyle = body.style; + + const font = computedStyle.getPropertyValue('--vscode-font-family').trim(); + if (font) { + bodyStyle.setProperty('--font-family', font); + bodyStyle.setProperty('--font-size', computedStyle.getPropertyValue('--vscode-font-size').trim()); + bodyStyle.setProperty('--font-weight', computedStyle.getPropertyValue('--vscode-font-weight').trim()); + } + else { + bodyStyle.setProperty( + '--font-family', + computedStyle.getPropertyValue('--vscode-editor-font-family').trim() + ); + bodyStyle.setProperty('--font-size', computedStyle.getPropertyValue('--vscode-editor-font-size').trim()); + bodyStyle.setProperty( + '--font-weight', + computedStyle.getPropertyValue('--vscode-editor-font-weight').trim() + ); + } + + let color = computedStyle.getPropertyValue('--vscode-editor-background').trim(); + bodyStyle.setProperty('--color-background', color); + bodyStyle.setProperty('--color-background--lighten-05', lighten(color, 5)); + bodyStyle.setProperty('--color-background--darken-05', darken(color, 5)); + bodyStyle.setProperty('--color-background--lighten-075', lighten(color, 7.5)); + bodyStyle.setProperty('--color-background--darken-075', darken(color, 7.5)); + bodyStyle.setProperty('--color-background--lighten-15', lighten(color, 15)); + bodyStyle.setProperty('--color-background--darken-15', darken(color, 15)); + bodyStyle.setProperty('--color-background--lighten-30', lighten(color, 30)); + bodyStyle.setProperty('--color-background--darken-30', darken(color, 30)); + + color = computedStyle.getPropertyValue('--vscode-button-background').trim(); + bodyStyle.setProperty('--color-button-background', color); + bodyStyle.setProperty('--color-button-background--darken-30', darken(color, 30)); + + color = computedStyle.getPropertyValue('--vscode-button-foreground').trim(); + bodyStyle.setProperty('--color-button-foreground', color); + + color = computedStyle.getPropertyValue('--vscode-editor-foreground').trim(); + if (!color) { + color = computedStyle.getPropertyValue('--vscode-foreground').trim(); + } + bodyStyle.setProperty('--color-foreground', color); + bodyStyle.setProperty('--color-foreground--85', opacity(color, 85)); + bodyStyle.setProperty('--color-foreground--75', opacity(color, 75)); + bodyStyle.setProperty('--color-foreground--50', opacity(color, 50)); + + color = computedStyle.getPropertyValue('--vscode-focusBorder').trim(); + bodyStyle.setProperty('--color-focus-border', color); + + color = computedStyle.getPropertyValue('--vscode-textLink-foreground').trim(); + bodyStyle.setProperty('--color-link-foreground', color); + bodyStyle.setProperty('--color-link-foreground--darken-20', darken(color, 20)); + }; + + const observer = new MutationObserver(onColorThemeChanged); + observer.observe(document.body, { attributes: true, attributeFilter: ['class'] }); + + onColorThemeChanged(); + return observer; +} diff --git a/src/ui/welcome/index.html b/src/webviews/apps/welcome/index.html similarity index 99% rename from src/ui/welcome/index.html rename to src/webviews/apps/welcome/index.html index b54174a..3b8f5eb 100644 --- a/src/ui/welcome/index.html +++ b/src/webviews/apps/welcome/index.html @@ -1132,9 +1132,7 @@ >
  • - Star me on GitHub
  • @@ -1194,7 +1192,6 @@ - diff --git a/src/webviews/apps/welcome/index.ts b/src/webviews/apps/welcome/index.ts new file mode 100644 index 0000000..4cc23dc --- /dev/null +++ b/src/webviews/apps/welcome/index.ts @@ -0,0 +1,16 @@ +'use strict'; +/*global window*/ +import { WelcomeBootstrap } from '../../protocol'; +// import { Snow } from './snow'; +import { AppWithConfig } from '../shared/appWithConfigBase'; + +const bootstrap: WelcomeBootstrap = (window as any).bootstrap; + +export class WelcomeApp extends AppWithConfig { + constructor() { + super('WelcomeApp', bootstrap); + } +} + +new WelcomeApp(); +// requestAnimationFrame(() => new Snow()); diff --git a/src/ui/welcome/snow.ts b/src/webviews/apps/welcome/snow.ts similarity index 100% rename from src/ui/welcome/snow.ts rename to src/webviews/apps/welcome/snow.ts diff --git a/src/webviews/protocol.ts b/src/webviews/protocol.ts new file mode 100644 index 0000000..8cf0809 --- /dev/null +++ b/src/webviews/protocol.ts @@ -0,0 +1,68 @@ +'use strict'; +import { Config } from '../config'; + +export interface IpcMessage { + id: string; + method: string; + params?: any; +} + +export type IpcNotificationParamsOf = NT extends IpcNotificationType ? P : never; +export class IpcNotificationType

    { + constructor(public readonly method: string) {} +} + +export type IpcCommandParamsOf = CT extends IpcCommandType ? P : never; +export class IpcCommandType

    { + constructor(public readonly method: string) {} +} + +export function onIpcCommand( + type: CT, + command: IpcMessage, + fn: (params: IpcCommandParamsOf) => void +) { + fn(command.params); +} + +export function onIpcNotification( + type: NT, + notification: IpcMessage, + fn: (params: IpcNotificationParamsOf) => void +) { + fn(notification.params); +} + +export interface DidChangeConfigurationNotificationParams { + config: Config; +} +export const DidChangeConfigurationNotificationType = new IpcNotificationType( + 'configuration/didChange' +); + +export interface UpdateConfigurationCommandParams { + changes: { + [key: string]: any; + }; + removes: string[]; + scope: 'user' | 'workspace'; + uri?: string; +} +export const UpdateConfigurationCommandType = new IpcCommandType( + 'configuration/update' +); + +export interface AppBootstrap {} + +export interface AppWithConfigBootstrap { + config: Config; +} + +export interface SettingsBootstrap extends AppWithConfigBootstrap { + scope: 'user' | 'workspace'; + scopes: ['user' | 'workspace', string][]; +} + +export interface WelcomeBootstrap extends AppWithConfigBootstrap {} + +export interface HistoryBootstrap {} diff --git a/src/webviews/settingsEditor.ts b/src/webviews/settingsWebview.ts similarity index 87% rename from src/webviews/settingsEditor.ts rename to src/webviews/settingsWebview.ts index f75fa1f..50fd065 100644 --- a/src/webviews/settingsEditor.ts +++ b/src/webviews/settingsWebview.ts @@ -2,10 +2,10 @@ import { commands, workspace } from 'vscode'; import { Commands } from '../commands'; import { Config, configuration } from '../configuration'; -import { SettingsBootstrap } from '../ui/ipc'; -import { WebviewEditor } from './webviewEditor'; +import { SettingsBootstrap } from './protocol'; +import { WebviewBase } from './webviewBase'; -export class SettingsEditor extends WebviewEditor { +export class SettingsWebview extends WebviewBase { constructor() { super(); } diff --git a/src/webviews/webviewEditor.ts b/src/webviews/webviewBase.ts similarity index 62% rename from src/webviews/webviewEditor.ts rename to src/webviews/webviewBase.ts index d826aa8..a654990 100644 --- a/src/webviews/webviewEditor.ts +++ b/src/webviews/webviewBase.ts @@ -1,4 +1,5 @@ 'use strict'; +import * as paths from 'path'; import * as fs from 'fs'; import { ConfigurationChangeEvent, @@ -14,9 +15,18 @@ import { import { Config, configuration } from '../configuration'; import { Container } from '../container'; import { Logger } from '../logger'; -import { Message, SettingsChangedMessage } from '../ui/ipc'; +import { + DidChangeConfigurationNotificationType, + IpcMessage, + IpcNotificationParamsOf, + IpcNotificationType, + onIpcCommand, + UpdateConfigurationCommandType +} from './protocol'; + +let ipcSequence = 0; -export abstract class WebviewEditor implements Disposable { +export abstract class WebviewBase implements Disposable { private _disposable: Disposable | undefined; private _disposablePanel: Disposable | undefined; private _panel: WebviewPanel | undefined; @@ -41,7 +51,7 @@ export abstract class WebviewEditor implements Disposable { } private onConfigurationChanged(e: ConfigurationChangeEvent) { - this.postUpdatedConfiguration(); + this.notifyDidChangeConfiguration(); } private onPanelDisposed() { @@ -51,38 +61,48 @@ export abstract class WebviewEditor implements Disposable { private onViewStateChanged(e: WebviewPanelOnDidChangeViewStateEvent) { Logger.log( - 'WebviewEditor.onViewStateChanged', + `Webview(${this.id}).onViewStateChanged`, `active=${e.webviewPanel.active}, visible=${e.webviewPanel.visible}` ); // Anytime the webview becomes active, make sure it has the most up-to-date config if (e.webviewPanel.active) { - this.postUpdatedConfiguration(); + this.notifyDidChangeConfiguration(); } } - protected async onMessageReceived(e: Message) { + protected onMessageReceived(e: IpcMessage) { + // virtual + } + + private onMessageReceivedCore(e: IpcMessage) { if (e == null) return; - Logger.log(`WebviewEditor.onMessageReceived: type=${e.type}, data=${JSON.stringify(e)}`); + Logger.log(`Webview(${this.id}).onMessageReceived: method=${e.method}, data=${JSON.stringify(e)}`); - switch (e.type) { - case 'saveSettings': { - const target = e.scope === 'workspace' ? ConfigurationTarget.Workspace : ConfigurationTarget.Global; + switch (e.method) { + case UpdateConfigurationCommandType.method: + onIpcCommand(UpdateConfigurationCommandType, e, async params => { + const target = + params.scope === 'workspace' ? ConfigurationTarget.Workspace : ConfigurationTarget.Global; - for (const key in e.changes) { - const inspect = await configuration.inspect(key)!; + for (const key in params.changes) { + const inspect = await configuration.inspect(key)!; - const value = e.changes[key]; - await configuration.update(key, value === inspect.defaultValue ? undefined : value, target); - } + const value = params.changes[key]; + await configuration.update(key, value === inspect.defaultValue ? undefined : value, target); + } - for (const key of e.removes) { - await configuration.update(key, undefined, target); - } + for (const key of params.removes) { + await configuration.update(key, undefined, target); + } + }); + + break; + default: + this.onMessageReceived(e); break; - } } } @@ -117,7 +137,7 @@ export abstract class WebviewEditor implements Disposable { this._panel, this._panel.onDidDispose(this.onPanelDisposed, this), this._panel.onDidChangeViewState(this.onViewStateChanged, this), - this._panel.webview.onDidReceiveMessage(this.onMessageReceived, this) + this._panel.webview.onDidReceiveMessage(this.onMessageReceivedCore, this) ); this._panel.webview.html = html; @@ -132,11 +152,13 @@ export abstract class WebviewEditor implements Disposable { private _html: string | undefined; private async getHtml(): Promise { + const filename = Container.context.asAbsolutePath(paths.join('dist/webviews/', this.filename)); + let content; // When we are debugging avoid any caching so that we can change the html and have it update without reloading if (Logger.isDebugging) { content = await new Promise((resolve, reject) => { - fs.readFile(Container.context.asAbsolutePath(this.filename), 'utf8', (err, data) => { + fs.readFile(filename, 'utf8', (err, data) => { if (err) { reject(err); } @@ -149,7 +171,7 @@ export abstract class WebviewEditor implements Disposable { else { if (this._html !== undefined) return this._html; - const doc = await workspace.openTextDocument(Container.context.asAbsolutePath(this.filename)); + const doc = await workspace.openTextDocument(filename); content = doc.getText(); } @@ -167,18 +189,29 @@ export abstract class WebviewEditor implements Disposable { return this._html; } - private postMessage(message: Message) { - if (this._panel === undefined) return false; + protected notify(type: NT, params: IpcNotificationParamsOf): Thenable { + return this.postMessage({ id: this.nextIpcId(), method: type.method, params: params }); + } + + private nextIpcId() { + if (ipcSequence === Number.MAX_SAFE_INTEGER) { + ipcSequence = 1; + } + else { + ipcSequence++; + } - return this._panel!.webview.postMessage(message); + return `host:${ipcSequence}`; } - private postUpdatedConfiguration() { + private notifyDidChangeConfiguration() { // Make sure to get the raw config, not from the container which has the modes mixed in - const msg: SettingsChangedMessage = { - type: 'settingsChanged', - config: configuration.get() - }; - return this.postMessage(msg); + return this.notify(DidChangeConfigurationNotificationType, { config: configuration.get() }); + } + + private postMessage(message: IpcMessage) { + if (this._panel === undefined) return Promise.resolve(false); + + return this._panel.webview.postMessage(message); } } diff --git a/src/webviews/welcomeEditor.ts b/src/webviews/welcomeWebview.ts similarity index 78% rename from src/webviews/welcomeEditor.ts rename to src/webviews/welcomeWebview.ts index 6e37aeb..3c3f9b3 100644 --- a/src/webviews/welcomeEditor.ts +++ b/src/webviews/welcomeWebview.ts @@ -2,10 +2,10 @@ import { commands } from 'vscode'; import { Commands } from '../commands'; import { Container } from '../container'; -import { WelcomeBootstrap } from '../ui/ipc'; -import { WebviewEditor } from './webviewEditor'; +import { WelcomeBootstrap } from './protocol'; +import { WebviewBase } from './webviewBase'; -export class WelcomeEditor extends WebviewEditor { +export class WelcomeWebview extends WebviewBase { constructor() { super(); } diff --git a/tsconfig.json b/tsconfig.json index 55261ec..d558f2c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,5 +15,5 @@ "strict": true, "target": "es2018" }, - "exclude": ["node_modules", "test", "src/ui"] + "exclude": ["node_modules", "test", "src/webviews/apps"] } diff --git a/tslint.json b/tslint.json deleted file mode 100644 index 51f12fa..0000000 --- a/tslint.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "extends": ["tslint-prettiest"], - "rules": { - "adjacent-overload-signatures": true, - "array-type": [true, "array"], - "arrow-parens": [true, "ban-single-arg-parens"], - "arrow-return-shorthand": true, - "class-name": true, - "comment-format": [true, "check-space"], - "curly": [true, "ignore-same-line"], - "eofline": true, - "interface-over-type-literal": true, - "linebreak-style": [true, "LF"], - "new-parens": true, - "no-angle-bracket-type-assertion": true, - "no-consecutive-blank-lines": [true, 1], - "no-default-export": true, - "no-duplicate-variable": true, - "no-eval": true, - "no-floating-promises": true, - "no-inferrable-types": [true, "ignore-params", "ignore-properties"], - "no-internal-module": true, - "no-irregular-whitespace": true, - "no-reference": true, - "no-string-throw": true, - "no-trailing-whitespace": true, - "no-unnecessary-callback-wrapper": true, - "no-unsafe-finally": true, - "no-unused-expression": false, - "no-var-keyword": true, - "no-var-requires": false, - "object-literal-key-quotes": [true, "as-needed"], - "one-line": [true, "check-open-brace", "check-whitespace"], - "one-variable-per-declaration": [true, "ignore-for-loop"], - "ordered-imports": [ - true, - { - "import-sources-order": "case-insensitive", - "named-imports-order": "case-insensitive" - } - ], - "prefer-const": true, - "prefer-for-of": true, - "prefer-method-signature": true, - "prefer-template": [true, "allow-single-concat"], - "prettiest": [true, "spaces", 4], - "quotemark": [true, "single", "avoid-escape"], - "radix": true, - "semicolon": [true, "always"], - "space-before-function-paren": [ - true, - { - "anonymous": "never", - "named": "never", - "asyncArrow": "always" - } - ], - "trailing-comma": [ - true, - { - "multiline": "never", - "singleline": "never" - } - ], - "triple-equals": [true, "allow-null-check"], - "typedef-whitespace": [ - true, - { - "call-signature": "nospace", - "index-signature": "nospace", - "parameter": "nospace", - "property-declaration": "nospace", - "variable-declaration": "nospace" - } - ], - "use-isnan": true, - "variable-name": [true, "allow-leading-underscore", "allow-pascal-case", "ban-keywords", "check-format"], - "whitespace": [ - true, - "check-branch", - "check-decl", - "check-operator", - "check-module", - "check-separator", - "check-type" - ] - }, - "defaultSeverity": "warning" -} diff --git a/webpack.config.js b/webpack.config.js index ac9e698..9998f7e 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -6,6 +6,7 @@ const webpack = require('webpack'); const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; const CleanPlugin = require('clean-webpack-plugin'); const CircularDependencyPlugin = require('circular-dependency-plugin'); +const HtmlExcludeAssetsPlugin = require('html-webpack-exclude-assets-plugin'); const HtmlInlineSourcePlugin = require('html-webpack-inline-source-plugin'); const HtmlPlugin = require('html-webpack-plugin'); const ImageminPlugin = require('imagemin-webpack-plugin').default; @@ -122,9 +123,9 @@ function getExtensionConfig(env) { } function getUIConfig(env) { - const clean = ['settings.html', 'welcome.html']; + const clean = []; if (env.optimizeImages) { - console.log('Optimizing images (src/ui/images/settings/*.png)...'); + console.log('Optimizing images (src/webviews/apps/images/settings/*.png)...'); clean.push('images/settings'); } @@ -134,11 +135,12 @@ function getUIConfig(env) { filename: '[name].css' }), new HtmlPlugin({ + excludeAssets: [/main\.js/], excludeChunks: ['welcome'], template: 'settings/index.html', - filename: path.resolve(__dirname, 'settings.html'), + filename: path.resolve(__dirname, 'dist/webviews/settings.html'), inject: true, - inlineSource: env.production ? '.(js|css)$' : undefined, + // inlineSource: env.production ? '.(js|css)$' : undefined, minify: env.production ? { removeComments: true, @@ -153,11 +155,12 @@ function getUIConfig(env) { : false }), new HtmlPlugin({ + excludeAssets: [/main\.js/], excludeChunks: ['settings'], template: 'welcome/index.html', - filename: path.resolve(__dirname, 'welcome.html'), + filename: path.resolve(__dirname, 'dist/webviews/welcome.html'), inject: true, - inlineSource: env.production ? '.(js|css)$' : undefined, + // inlineSource: env.production ? '.(js|css)$' : undefined, minify: env.production ? { removeComments: true, @@ -171,12 +174,13 @@ function getUIConfig(env) { } : false }), + new HtmlExcludeAssetsPlugin(), new HtmlInlineSourcePlugin(), new ImageminPlugin({ disable: !env.optimizeImages, externalImages: { - context: path.resolve(__dirname, 'src/ui/images'), - sources: glob.sync('src/ui/images/settings/*.png'), + context: path.resolve(__dirname, 'src/webviews/apps/images'), + sources: glob.sync('src/webviews/apps/images/settings/*.png'), destination: path.resolve(__dirname, 'images') }, cacheFolder: path.resolve(__dirname, '.cache-images'), @@ -192,20 +196,19 @@ function getUIConfig(env) { ]; return { - name: 'ui', - context: path.resolve(__dirname, 'src/ui'), - // This is ugly having main.scss on both bundles, but if it is added separately it will generate a js bundle :( + name: 'webviews', + context: path.resolve(__dirname, 'src/webviews/apps'), entry: { - settings: ['./settings/index.ts', './scss/main.scss'], - welcome: ['./welcome/index.ts', './scss/main.scss'] - // main: ['./scss/main.scss'] + main: ['./scss/main.scss'], + settings: ['./settings/index.ts'], + welcome: ['./welcome/index.ts'] }, mode: env.production ? 'production' : 'development', devtool: env.production ? undefined : 'eval-source-map', output: { filename: '[name].js', - path: path.resolve(__dirname, 'dist/ui'), - publicPath: '{{root}}/dist/ui/' + path: path.resolve(__dirname, 'dist/webviews'), + publicPath: '{{root}}/dist/webviews/' }, module: { rules: [ @@ -228,7 +231,7 @@ function getUIConfig(env) { use: { loader: 'ts-loader', options: { - configFile: 'ui.tsconfig.json' + configFile: 'webviews.tsconfig.json' } }, exclude: /node_modules|\.d\.ts$/ @@ -259,7 +262,7 @@ function getUIConfig(env) { }, resolve: { extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'], - modules: [path.resolve(__dirname, 'src/ui'), 'node_modules'] + modules: [path.resolve(__dirname, 'src/webviews/apps'), 'node_modules'] }, plugins: plugins, stats: { diff --git a/ui.tsconfig.json b/webviews.tsconfig.json similarity index 80% rename from ui.tsconfig.json rename to webviews.tsconfig.json index 04adffa..4d4c351 100644 --- a/ui.tsconfig.json +++ b/webviews.tsconfig.json @@ -8,13 +8,13 @@ "noFallthroughCasesInSwitch": true, "noImplicitReturns": true, "noUnusedLocals": false, - "outDir": "dist/ui", + "outDir": "dist/webviews", "rootDir": "src", "skipLibCheck": true, "sourceMap": true, "strict": true, "target": "es2018" }, - "include": ["src/config.ts", "src/ui/**/*"], + "include": ["src/config.ts", "src/webviews/protocol.ts", "src/webviews/apps/**/*"], "exclude": ["node_modules"] }