├── .all-contributorsrc
├── .azure-pipelines
├── build.docs.yml
├── build.yml
├── create-release.docs.yml
├── lint.yml
├── package.yml
├── publish-release.docs.yml
├── release.docs.yml
├── test.yml
└── upload-docs.sh
├── .eslintrc
├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── PULL_REQUEST_TEMPLATE
│ └── pull_request_template.md
└── workflows
│ └── azure-static-web-apps-agreeable-plant-079b5480f.yml
├── .gitignore
├── .prettierrc.js
├── .vscode
├── extensions.json
├── launch.json
├── settings.json
└── tasks.json
├── .vscodeignore
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE.md
├── README.md
├── azure-pipelines.docs.old.yml
├── azure-pipelines.yml
├── docs
├── .vuepress
│ ├── config.js
│ ├── dist
│ │ ├── 404.html
│ │ ├── about
│ │ │ ├── code_of_conduct.html
│ │ │ ├── contributing.html
│ │ │ ├── history.html
│ │ │ └── license.html
│ │ ├── assets
│ │ │ ├── affected-settings.jpg
│ │ │ ├── css
│ │ │ │ └── styles.baa9963c.css
│ │ │ ├── element-adjustments.png
│ │ │ ├── hero.png
│ │ │ ├── img
│ │ │ │ └── back-to-top.8b37f773.svg
│ │ │ ├── js
│ │ │ │ ├── 293.bdc27997.js
│ │ │ │ ├── 491.f3d3f538.js
│ │ │ │ ├── 812.5c9465d6.js
│ │ │ │ ├── 812.5c9465d6.js.LICENSE.txt
│ │ │ │ ├── app.71908e55.js
│ │ │ │ ├── runtime~app.8fcc392a.js
│ │ │ │ ├── v-05b2f426.62b5ae63.js
│ │ │ │ ├── v-3706649a.4fa7f288.js
│ │ │ │ ├── v-510ed0d4.fedc348e.js
│ │ │ │ ├── v-5993bf33.64e26bd3.js
│ │ │ │ ├── v-8daa1a0e.c4599b90.js
│ │ │ │ ├── v-d585fbd8.d7742574.js
│ │ │ │ ├── v-f6faca80.3fe5eae0.js
│ │ │ │ └── v-fffb8e28.736cfea0.js
│ │ │ ├── named-colors.gif
│ │ │ ├── peacock-3-instances.gif
│ │ │ ├── peacock-icon-small.png
│ │ │ ├── peacock-icon.png
│ │ │ ├── peacock-live-share-demo.gif
│ │ │ ├── peacock-remote.gif
│ │ │ ├── peacock-sketchnote.png
│ │ │ ├── peacock-windows.png
│ │ │ └── title-bar-coloring-settings.png
│ │ ├── changelog
│ │ │ └── index.html
│ │ ├── guide
│ │ │ └── index.html
│ │ └── index.html
│ ├── public
│ │ └── assets
│ │ │ ├── affected-settings.png
│ │ │ ├── element-adjustments.png
│ │ │ ├── hero.png
│ │ │ ├── named-colors.gif
│ │ │ ├── peacock-3-instances.gif
│ │ │ ├── peacock-icon-small.png
│ │ │ ├── peacock-icon.png
│ │ │ ├── peacock-live-share-demo.gif
│ │ │ ├── peacock-remote.gif
│ │ │ ├── peacock-sketchnote.png
│ │ │ ├── peacock-windows.png
│ │ │ └── title-bar-coloring-settings.png
│ └── styles
│ │ ├── index.scss
│ │ └── palette.scss
├── README.md
├── about
│ ├── code_of_conduct.md
│ ├── contributing.md
│ ├── history.md
│ └── license.md
├── changelog
│ └── README.md
└── guide
│ └── README.md
├── package-lock.json
├── package.json
├── resources
├── hero.png
├── peacock-icon-small.png
└── peacock-icon.png
├── src
├── apply-color.ts
├── color-library.ts
├── commands.ts
├── configuration
│ ├── index.ts
│ ├── read-configuration.ts
│ └── update-configuration.ts
├── extension.ts
├── inputs.ts
├── live-share
│ ├── enums.ts
│ ├── index.ts
│ ├── integration.ts
│ ├── liveshare-commands.ts
│ └── test
│ │ ├── runTest.ts
│ │ └── suite
│ │ ├── index.ts
│ │ └── live-share.test.ts
├── logging.ts
├── mementos.ts
├── models
│ ├── constants.ts
│ ├── enums.ts
│ ├── favorites.ts
│ ├── index.ts
│ ├── interfaces.ts
│ └── state.ts
├── notification.ts
├── object-library.ts
├── remote
│ ├── enums.ts
│ ├── index.ts
│ └── integration.ts
├── statusbar.ts
└── test
│ ├── coverage.ts
│ ├── runTest.ts
│ └── suite
│ ├── affected-elements.test.ts
│ ├── basic.test.ts
│ ├── built-in-colors.test.ts
│ ├── color-input.test.ts
│ ├── config-changes.test.ts
│ ├── current-color.test.ts
│ ├── darken-lighten.test.ts
│ ├── documentation.test.ts
│ ├── editing-color-settings.test.ts
│ ├── element-adjustments.test.ts
│ ├── favorite-colors.test.ts
│ ├── foreground.test.ts
│ ├── index.ts
│ ├── lib
│ ├── constants.ts
│ └── setup-teardown-test-suite.ts
│ ├── notification.test.ts
│ ├── remote.test.ts
│ ├── reset.test.ts
│ ├── save-favorite-color.test.ts
│ ├── save-starter-favorite-colors.test.ts
│ ├── status-bar.test.ts
│ └── surprise-me-on-startup.test.ts
├── testworkspace
└── .vscode
│ └── settings.json
├── tsconfig.json
├── vsc-extension-quickstart.md
└── webpack.config.js
/.all-contributorsrc:
--------------------------------------------------------------------------------
1 | {
2 | "files": [
3 | "README.md"
4 | ],
5 | "imageSize": 100,
6 | "commit": false,
7 | "contributors": [
8 | {
9 | "login": "musicfuel",
10 | "name": "James Newell",
11 | "avatar_url": "https://avatars1.githubusercontent.com/u/1085791?v=4",
12 | "profile": "https://github.com/musicfuel",
13 | "contributions": [
14 | "test"
15 | ]
16 | },
17 | {
18 | "login": "JulianG",
19 | "name": "Julian",
20 | "avatar_url": "https://avatars1.githubusercontent.com/u/237818?v=4",
21 | "profile": "https://juliangaramendy.dev",
22 | "contributions": [
23 | "ideas"
24 | ]
25 | },
26 | {
27 | "login": "legomushroom",
28 | "name": "Oleg Solomka",
29 | "avatar_url": "https://avatars2.githubusercontent.com/u/1478800?v=4",
30 | "profile": "https://twitter.com/legomushroom",
31 | "contributions": [
32 | "code",
33 | "test"
34 | ]
35 | },
36 | {
37 | "login": "josephrexme",
38 | "name": "Joseph Rex",
39 | "avatar_url": "https://avatars3.githubusercontent.com/u/5395567?v=4",
40 | "profile": "https://josephrex.me",
41 | "contributions": [
42 | "design"
43 | ]
44 | },
45 | {
46 | "login": "samjulien",
47 | "name": "Sam Julien",
48 | "avatar_url": "https://avatars1.githubusercontent.com/u/7738189?v=4",
49 | "profile": "http://www.samjulien.com",
50 | "contributions": [
51 | "ideas"
52 | ]
53 | },
54 | {
55 | "login": "spboyer",
56 | "name": "Shayne Boyer",
57 | "avatar_url": "https://avatars1.githubusercontent.com/u/7681382?v=4",
58 | "profile": "http://www.tattoocoder.com",
59 | "contributions": [
60 | "code"
61 | ]
62 | },
63 | {
64 | "login": "burkeholland",
65 | "name": "Burke Holland",
66 | "avatar_url": "https://avatars1.githubusercontent.com/u/686963?v=4",
67 | "profile": "http://a.shinynew.me",
68 | "contributions": [
69 | "ideas"
70 | ]
71 | },
72 | {
73 | "login": "lostintangent",
74 | "name": "Jonathan Carter",
75 | "avatar_url": "https://avatars3.githubusercontent.com/u/116461?v=4",
76 | "profile": "http://www.lostintangent.com",
77 | "contributions": [
78 | "code"
79 | ]
80 | },
81 | {
82 | "login": "souzara",
83 | "name": "Ricardo Souza",
84 | "avatar_url": "https://avatars2.githubusercontent.com/u/11986361?v=4",
85 | "profile": "https://github.com/souzara",
86 | "contributions": [
87 | "code"
88 | ]
89 | },
90 | {
91 | "login": "kushalpandya",
92 | "name": "Kushal Pandya",
93 | "avatar_url": "https://avatars1.githubusercontent.com/u/1748044?v=4",
94 | "profile": "https://doublslash.com",
95 | "contributions": [
96 | "code"
97 | ]
98 | },
99 | {
100 | "login": "egamma",
101 | "name": "Erich Gamma",
102 | "avatar_url": "https://avatars1.githubusercontent.com/u/172399?v=4",
103 | "profile": "https://github.com/egamma",
104 | "contributions": [
105 | "test"
106 | ]
107 | },
108 | {
109 | "login": "christiannwamba",
110 | "name": "Christian Nwamba",
111 | "avatar_url": "https://avatars2.githubusercontent.com/u/8108337?v=4",
112 | "profile": "https://github.com/christiannwamba",
113 | "contributions": [
114 | "ideas"
115 | ]
116 | },
117 | {
118 | "login": "mjbvz",
119 | "name": "Matt Bierner",
120 | "avatar_url": "https://avatars2.githubusercontent.com/u/12821956?v=4",
121 | "profile": "http://mattbierner.com",
122 | "contributions": [
123 | "code"
124 | ]
125 | },
126 | {
127 | "login": "cfjedimaster",
128 | "name": "Raymond Camden",
129 | "avatar_url": "https://avatars3.githubusercontent.com/u/393660?v=4",
130 | "profile": "https://www.raymondcamden.com",
131 | "contributions": [
132 | "ideas"
133 | ]
134 | },
135 | {
136 | "login": "aaronpowell",
137 | "name": "Aaron Powell",
138 | "avatar_url": "https://avatars0.githubusercontent.com/u/434140?v=4",
139 | "profile": "http://www.aaron-powell.com",
140 | "contributions": [
141 | "ideas"
142 | ]
143 | },
144 | {
145 | "login": "tanhakabir",
146 | "name": "tanhakabir",
147 | "avatar_url": "https://avatars.githubusercontent.com/u/12758612?v=4",
148 | "profile": "https://github.com/tanhakabir",
149 | "contributions": [
150 | "code"
151 | ]
152 | },
153 | {
154 | "login": "ndrake",
155 | "name": "Nate Drake",
156 | "avatar_url": "https://avatars.githubusercontent.com/u/73789?v=4",
157 | "profile": "https://github.com/ndrake",
158 | "contributions": [
159 | "code"
160 | ]
161 | }
162 | ],
163 | "contributorsPerLine": 7,
164 | "projectName": "vscode-peacock",
165 | "projectOwner": "johnpapa",
166 | "repoType": "github",
167 | "repoHost": "https://github.com",
168 | "skipCi": true
169 | }
170 |
--------------------------------------------------------------------------------
/.azure-pipelines/build.docs.yml:
--------------------------------------------------------------------------------
1 | steps:
2 | - task: NodeTool@0
3 | displayName: 'Use $(node_version)'
4 | inputs:
5 | versionSpec: $(node_version)
6 |
7 | - task: Npm@1
8 | displayName: 'Install dependencies'
9 | inputs:
10 | verbose: false
11 | command: install
12 |
13 | - task: Npm@1
14 | displayName: 'Compile Extension'
15 | inputs:
16 | command: custom
17 | verbose: false
18 | customCommand: 'run docs:build'
19 |
--------------------------------------------------------------------------------
/.azure-pipelines/build.yml:
--------------------------------------------------------------------------------
1 | steps:
2 | - task: NodeTool@0
3 | displayName: 'Use $(node_version)'
4 | inputs:
5 | versionSpec: $(node_version)
6 |
7 | - task: Npm@1
8 | displayName: 'Install dependencies'
9 | inputs:
10 | verbose: false
11 | command: install
12 |
13 | - task: Npm@1
14 | displayName: 'Compile Extension'
15 | inputs:
16 | command: custom
17 | verbose: false
18 | customCommand: 'run test-compile'
19 |
--------------------------------------------------------------------------------
/.azure-pipelines/create-release.docs.yml:
--------------------------------------------------------------------------------
1 | steps:
2 | # Archive files
3 | # Compress files into .7z, .tar.gz, or .zip
4 | - task: ArchiveFiles@2
5 | displayName: 'Create Docs Pipeline Artifact'
6 | inputs:
7 | rootFolderOrFile: '$(Build.SourcesDirectory)/docs/.vuepress/dist'
8 | includeRootFolder: false
9 | archiveType: 'zip' # Options: zip, 7z, tar, wim
10 | #tarCompression: 'gz' # Optional. Options: gz, bz2, xz, none
11 | archiveFile: '$(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip'
12 | replaceExistingArchive: true
13 | #verbose: # Optional
14 | #quiet: # Optional
15 | condition: succeeded()
16 |
17 | # - task: PublishPipelineArtifact@0
18 | # displayName: 'Publish Docs Pipeline Artifact'
19 | # inputs:
20 | # targetPath: '$(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip'
21 | # condition: succeeded()
22 |
23 | # Publish build artifacts
24 | # Publish build artifacts to Azure Pipelines or a Windows file share
25 | - task: PublishBuildArtifacts@1
26 | inputs:
27 | pathtoPublish: '$(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip'
28 | artifactName: 'MyDocsOutput'
29 | publishLocation: 'Container' # Options: container, filePath
30 | #targetPath: # Required when publishLocation == FilePath
31 | #parallel: false # Optional
32 | #parallelCount: # Optional
33 | condition: succeeded()
34 |
--------------------------------------------------------------------------------
/.azure-pipelines/lint.yml:
--------------------------------------------------------------------------------
1 | steps:
2 | - task: Npm@1
3 | displayName: 'Lint'
4 | inputs:
5 | command: custom
6 | customCommand: run lint
7 |
--------------------------------------------------------------------------------
/.azure-pipelines/package.yml:
--------------------------------------------------------------------------------
1 | steps:
2 | - script: |
3 | npx vsce package -o release.vsix
4 | displayName: 'create vsix'
5 | condition: and(succeeded(), eq(variables['node_version'], '12.x'), eq(variables['Agent.OS'], 'Linux'))
6 |
7 | - task: PublishPipelineArtifact@0
8 | displayName: 'Publish Pipeline Artifact'
9 | inputs:
10 | targetPath: release.vsix
11 | # Only create the release for Linux on Node 12
12 | condition: and(succeeded(), eq(variables['node_version'], '12.x'), eq(variables['Agent.OS'], 'Linux'))
13 | # Instead of running this task and npm install and build again,
14 | # let's just create the vsix in a previous task to save time.
15 | # If one of them fails, the entire build fails anyway
16 | # - job: Finalize
17 | # dependsOn:
18 | # - macOS
19 | # - Linux
20 | # - Windows
21 | # condition: and(succeeded('macOS'), succeeded('Linux'), succeeded('Windows'))
22 | # pool:
23 | # # https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/hosted?view=azure-devops&tabs=yaml#use-a-microsoft-hosted-agent
24 | # name: Hosted macOS
25 | # demands: npm
26 | # steps:
27 | # - task: NodeTool@0
28 | # displayName: 'Use Node 8.x'
29 | # inputs:
30 | # versionSpec: 8.x
31 |
32 | # - task: Npm@1
33 | # displayName: 'Install dependencies'
34 | # inputs:
35 | # verbose: false
36 | # command: install
37 | # - task: Npm@1
38 | # displayName: 'Compile TypeScript'
39 | # inputs:
40 | # command: custom
41 | # verbose: false
42 | # customCommand: 'run compile'
43 | # enabled: true
44 | # - script: |
45 | # npx vsce package -o release.vsix
46 | # displayName: 'create vsix'
47 |
48 | # - task: PublishPipelineArtifact@0
49 | # displayName: 'Publish Pipeline Artifact'
50 | # inputs:
51 | # targetPath: release.vsix
52 |
--------------------------------------------------------------------------------
/.azure-pipelines/publish-release.docs.yml:
--------------------------------------------------------------------------------
1 | steps:
2 | - task: DownloadBuildArtifacts@0
3 | inputs:
4 | buildType: 'current'
5 | artifactName: 'MyDocsOutput'
6 | downloadType: 'single'
7 | downloadPath: '$(System.ArtifactsDirectory)'
8 |
9 | - task: ExtractFiles@1
10 | displayName: 'Extract what we just zipped - because'
11 | inputs:
12 | archiveFilePatterns: '$(System.ArtifactsDirectory)/*.zip'
13 | destinationFolder: '$(Build.ArtifactStagingDirectory)/extracted'
14 | cleanDestinationFolder: true
15 | condition: succeeded()
16 |
17 | - task: AzureCLI@1
18 | displayName: 'Upload the files to Azure Storage'
19 | inputs:
20 | azureSubscription: 'john.papa(cfd12dd7-4872-4b83-8cd8-2ed6083047d7)'
21 | scriptLocation: 'scriptPath'
22 | scriptPath: '.azure-pipelines/upload-docs.sh'
23 | arguments: '$(Build.ArtifactStagingDirectory)/extracted'
24 | condition: succeeded()
25 |
--------------------------------------------------------------------------------
/.azure-pipelines/release.docs.yml:
--------------------------------------------------------------------------------
1 | steps:
2 | - task: AzureCLI@1
3 | displayName: 'Upload the files to Azure Storage'
4 | inputs:
5 | azureSubscription: 'john.papa(cfd12dd7-4872-4b83-8cd8-2ed6083047d7)'
6 | scriptLocation: 'scriptPath'
7 | scriptPath: '.azure-pipelines/upload-docs.sh'
8 | arguments: '$(Build.SourcesDirectory)/docs/.vuepress/dist'
9 | condition: and(succeeded(), eq(variables['node_version'], '12.x'), eq(variables['Agent.OS'], 'Linux'))
10 |
--------------------------------------------------------------------------------
/.azure-pipelines/test.yml:
--------------------------------------------------------------------------------
1 | steps:
2 | # starts a process that allows the vscode test environment to run
3 | - script: |
4 | set -e
5 | /usr/bin/Xvfb :10 -ac >> /tmp/Xvfb.out 2>&1 &
6 | disown -ar
7 | displayName: 'Start xvfb'
8 | condition: eq(variables['Agent.OS'], 'Linux')
9 |
10 | - task: Npm@1
11 | displayName: 'Run Tests'
12 | env:
13 | DISPLAY: :10
14 | inputs:
15 | command: custom
16 | verbose: false
17 | customCommand: 'run test:coverage'
18 |
19 | - task: PublishTestResults@2
20 | displayName: 'Publish Test Results'
21 | inputs:
22 | testResultsFiles: 'out-cov/*-results.xml'
23 | testRunTitle: '$(Agent.OS)-$(node_version)'
24 | condition: succeededOrFailed()
25 |
26 | - task: PublishCodeCoverageResults@1
27 | inputs:
28 | codeCoverageTool: 'cobertura'
29 | summaryFileLocation: coverage/cobertura-coverage.xml
30 | reportDirectory: coverage/lcov-report
31 | condition: succeededOrFailed()
32 |
33 | # Uncomment to push results to CodeCov.io, will need a token in a secret variable
34 | # - bash: |
35 | # bash <(curl https://codecov.io/bash) -t $TOKEN -f coverage/cobertura-coverage.xml
36 | # displayName: 'codecov'
37 | # condition: succeededOrFailed()
38 | # env:
39 | # TOKEN: $(CODECOV_TOKEN)
--------------------------------------------------------------------------------
/.azure-pipelines/upload-docs.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | SOURCE=$1
3 |
4 | az storage blob upload-batch \
5 | -d '$web' \
6 | --account-name papapeacockstorage \
7 | -s $SOURCE \
8 | --pattern '*'
9 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "@typescript-eslint/parser",
3 | "plugins": ["@typescript-eslint"],
4 | "extends": [
5 | "plugin:@typescript-eslint/recommended",
6 | // "prettier",
7 | "prettier/@typescript-eslint",
8 | // "plugin:prettier/recommended" Enables eslint-plugin-prettier
9 | // and displays prettier errors as ESLint errors.
10 | // Make sure this is always the last configuration in the extends array.
11 | // "plugin:prettier/recommended"
12 | ],
13 | "parserOptions": {
14 | "project": "./tsconfig.json"
15 | },
16 | "rules": {
17 | "@typescript-eslint/explicit-function-return-type": "off",
18 | "@typescript-eslint/no-parameter-properties": "off",
19 | "@typescript-eslint/no-angle-bracket-type-assertion": "off",
20 | "@typescript-eslint/no-object-literal-type-assertion": "off",
21 | "@typescript-eslint/no-use-before-define": "off",
22 | "@typescript-eslint/no-explicit-any": "off",
23 | "@typescript-eslint/no-non-null-assertion": "off",
24 | "@typescript-eslint/interface-name-prefix": "off",
25 | "@typescript-eslint/camelcase": "off",
26 | "@typescript-eslint/explicit-member-accessibility": "off"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: [johnpapa]
2 | # patreon: patreon
3 | # custom: ["https://www.paypal.me/johnpapa1"]
4 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 | ---
8 |
9 | **Versions (please complete the following information):**
10 |
11 | - OS: [e.g. mac]
12 | - VS Code version [e.g. 1.37.0-insiders]
13 | - Peacock Version [e.g. 2.5.2]
14 |
15 | **Describe the bug**
16 | A clear and concise description of what the bug is.
17 |
18 | **To Reproduce**
19 | Steps to reproduce the behavior:
20 |
21 | 1. Go to '...'
22 | 2. Click on '....'
23 | 3. See error
24 |
25 | **Expected behavior**
26 | A clear and concise description of what you expected to happen.
27 |
28 | **Screenshots**
29 | If applicable, add screenshots to help explain your problem.
30 |
31 | **Additional context**
32 | Add any other context about the problem here.
33 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md:
--------------------------------------------------------------------------------
1 | # Title
2 |
3 | ## Purpose
4 |
5 | - ...
6 |
7 | ## What
8 |
9 | - ...
10 |
11 | ## How to Test
12 |
13 | - `npm test`
14 |
15 | ## Checklist of changes included
16 |
17 | - [ ] CHANGELOG updated
18 | - [ ] README updated
19 | - [ ] Tests updated/added
20 | - [ ] Prettier formatting
21 | - [ ] console.log removed
22 | - [ ] Dead code removed
23 | - [ ] Unnecessary comments removed
24 | - [ ] Images updated (if applicable)
25 | - [ ] Version updated everywhere
26 |
--------------------------------------------------------------------------------
/.github/workflows/azure-static-web-apps-agreeable-plant-079b5480f.yml:
--------------------------------------------------------------------------------
1 | name: Azure Static Web Apps CI/CD
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | pull_request:
8 | types: [opened, synchronize, reopened, closed]
9 | branches:
10 | - main
11 |
12 | jobs:
13 | build_and_deploy_job:
14 | if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
15 | runs-on: ubuntu-latest
16 | name: Build and Deploy Job
17 | steps:
18 | - uses: actions/checkout@v2
19 | with:
20 | submodules: true
21 | - name: Build And Deploy
22 | id: builddeploy
23 | uses: Azure/static-web-apps-deploy@v1
24 | with:
25 | azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_AGREEABLE_PLANT_079B5480F }}
26 | repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments)
27 | action: "upload"
28 | ###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
29 | # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
30 | app_location: "/" # App source code path
31 | # api_location: "api" # Api source code path - optional
32 | output_location: "docs/.vuepress/dist" # Built app content directory - optional
33 | app_build_command: 'npm run docs:build'
34 | ###### End of Repository/Build Configurations ######
35 |
36 | close_pull_request_job:
37 | if: github.event_name == 'pull_request' && github.event.action == 'closed'
38 | runs-on: ubuntu-latest
39 | name: Close Pull Request Job
40 | steps:
41 | - name: Close Pull Request
42 | id: closepullrequest
43 | uses: Azure/static-web-apps-deploy@v1
44 | with:
45 | azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_AGREEABLE_PLANT_079B5480F }}
46 | action: "close"
47 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | out
2 | node_modules
3 | .vscode-test/
4 | *.vsix
5 | dist
6 | !docs/.vuepress/dist
7 | out-cov
8 | coverage
9 | xunit.xml
10 | .vscode-test-web
11 | docs/.vuepress/.*
12 | .DS_Store
13 | .env
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | semi: true,
3 | trailingComma: 'all',
4 | singleQuote: true,
5 | printWidth: 100,
6 | tabWidth: 2,
7 | arrowParens: 'avoid'
8 | };
9 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // See http://go.microsoft.com/fwlink/?LinkId=827846
3 | // for the documentation about the extensions.json format
4 | "recommendations": [
5 | ]
6 | }
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | // A launch configuration that compiles the extension and then opens it inside a new window
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | {
6 | "version": "0.2.0",
7 | "configurations": [
8 | {
9 | "name": "Run Extension",
10 | "type": "extensionHost",
11 | "request": "launch",
12 | "runtimeExecutable": "${execPath}",
13 | "args": ["--extensionDevelopmentPath=${workspaceFolder}"],
14 | "outFiles": ["${workspaceFolder}/dist/**/*.js"],
15 | "preLaunchTask": "npm: webpack"
16 | },
17 | {
18 | "name": "Extension Tests",
19 | "type": "extensionHost",
20 | "request": "launch",
21 | "runtimeExecutable": "${execPath}",
22 | "args": [
23 | "${workspaceFolder}/testworkspace",
24 | "--disable-extensions",
25 | "--extensionDevelopmentPath=${workspaceFolder}",
26 | "--extensionTestsPath=${workspaceFolder}/out/test/suite/index"
27 | ],
28 | "outFiles": ["${workspaceFolder}/out/test/**/*.js"],
29 | "preLaunchTask": "npm: test-compile"
30 | },
31 | {
32 | "name": "Extension Tests - Live Share Integration",
33 | "type": "extensionHost",
34 | "request": "launch",
35 | "runtimeExecutable": "${execPath}",
36 | "args": [
37 | "${workspaceFolder}/testworkspace",
38 | "--extensionDevelopmentPath=${workspaceFolder}",
39 | "--extensionTestsPath=${workspaceFolder}/out/live-share/test/suite/index"
40 | ],
41 | "outFiles": ["${workspaceFolder}/out/test/**/*.js"],
42 | "preLaunchTask": "npm: test-compile"
43 | },
44 | {
45 | "name": "Run Web Extension in VS Code",
46 | "type": "pwa-extensionHost",
47 | "debugWebWorkerHost": true,
48 | "request": "launch",
49 | "args": [
50 | "--extensionDevelopmentPath=${workspaceFolder}",
51 | "--extensionDevelopmentKind=web"
52 | ],
53 | "outFiles": [
54 | "${workspaceFolder}/dist/**/*.js"
55 | ],
56 | "preLaunchTask": "npm: watch"
57 | },
58 | ]
59 | }
60 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | // Place your settings in this file to overwrite default and user settings.
2 | {
3 | "files.exclude": {
4 | "out": false // set this to true to hide the "out" folder with the compiled JS files
5 | },
6 | "search.exclude": {
7 | "out": true // set this to false to include "out" folder in search results
8 | },
9 | // Turn off tsc task auto detection since we have the necessary tasks as npm scripts
10 | "typescript.tsc.autoDetect": "off",
11 | "workbench.statusBar.visible": true,
12 | "peacock.color": "1857a4",
13 | "workbench.colorCustomizations": {
14 | "sash.hoverBorder": "#1857a4",
15 | "activityBar.activeBackground": "#1857a4",
16 | "activityBar.background": "#1857a4",
17 | "activityBar.foreground": "#e7e7e7",
18 | "activityBar.inactiveForeground": "#e7e7e799",
19 | "activityBarBadge.background": "#530c2c",
20 | "activityBarBadge.foreground": "#e7e7e7",
21 | "titleBar.activeBackground": "#1857a4",
22 | "titleBar.activeForeground": "#e7e7e7",
23 | "titleBar.inactiveBackground": "#1857a499",
24 | "titleBar.inactiveForeground": "#e7e7e799",
25 | "statusBar.background": "#1857a4",
26 | "statusBar.foreground": "#e7e7e7",
27 | "statusBarItem.hoverBackground": "#1f6fd0",
28 | "statusBarItem.remoteBackground": "#1857a4",
29 | "statusBarItem.remoteForeground": "#e7e7e7",
30 | "activityBar.activeBorder": "#530c2c",
31 | "commandCenter.border": "#e7e7e799"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | // See https://go.microsoft.com/fwlink/?LinkId=733558
2 | // for the documentation about the tasks.json format
3 | {
4 | "version": "2.0.0",
5 | "tasks": [
6 | {
7 | "type": "npm",
8 | "script": "watch",
9 | "problemMatcher": "$tsc-watch",
10 | "isBackground": true,
11 | "presentation": {
12 | "reveal": "never"
13 | },
14 | "group": {
15 | "kind": "build",
16 | "isDefault": true
17 | }
18 | },
19 | {
20 | "type": "npm",
21 | "script": "watch",
22 | "group": "build",
23 | "isBackground": true,
24 | "problemMatcher": [
25 | "$ts-webpack-watch",
26 | "$tslint-webpack-watch"
27 | ]
28 | }
29 | ]
30 | }
31 |
--------------------------------------------------------------------------------
/.vscodeignore:
--------------------------------------------------------------------------------
1 | .vscode/**
2 | .vscode-test/**
3 | out/test/**
4 | src/**
5 | .gitignore
6 | vsc-extension-quickstart.md
7 | **/tsconfig.json
8 | **/tslint.json
9 | **/*.map
10 | **/*.ts
11 |
12 | # Extra file to ignore
13 | azure-pipelines.yml
14 | .azure-pipelines/
15 | ISSUE_TEMPLATE.md
16 | PULL_REQUEST_TEMPLATE.md
17 | .github/
18 | vsc-extension-quickstart.md
19 | node_modules/**/test/**
20 | .all-contributorsrc
21 | node_modules
22 | out/
23 | src/
24 | tsconfig.json
25 | webpack.config.json
26 | coverage/
27 | out-cov/
28 | .eslintrc
29 | .prettierrc
30 | docs
31 | testworkspace
32 | webpack.config.js
33 | .prettierrc.js
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # CHANGELOG
2 |
3 | The changelog can be found in the extensive [documentation here](https://www.peacockcode.dev) which includes a guide on how to use Peacock and a [changelog](https://www.peacockcode.dev/changelog/)
4 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Code of Conduct
3 | # We can even add meta tags to the page! This sets the keywords meta tag.
4 | #
5 | description: Code of Conduct guide for the Visual Studio Code Peacock extension
6 | meta:
7 | - name: keywords
8 | - content: vscode "visual studio code" peacock theme extension Code of Conduct
9 | ---
10 | # Contributor Covenant Code of Conduct
11 |
12 | ## Our Pledge
13 |
14 | In the interest of fostering an open and welcoming environment, we as
15 | contributors and maintainers pledge to making participation in our project and
16 | our community a harassment-free experience for everyone, regardless of age, body
17 | size, disability, ethnicity, sex characteristics, gender identity and expression,
18 | level of experience, education, socio-economic status, nationality, personal
19 | appearance, race, religion, or sexual identity and orientation.
20 |
21 | ## Our Standards
22 |
23 | Examples of behavior that contributes to creating a positive environment
24 | include:
25 |
26 | * Using welcoming and inclusive language
27 | * Being respectful of differing viewpoints and experiences
28 | * Gracefully accepting constructive criticism
29 | * Focusing on what is best for the community
30 | * Showing empathy towards other community members
31 |
32 | Examples of unacceptable behavior by participants include:
33 |
34 | * The use of sexualized language or imagery and unwelcome sexual attention or
35 | advances
36 | * Trolling, insulting/derogatory comments, and personal or political attacks
37 | * Public or private harassment
38 | * Publishing others' private information, such as a physical or electronic
39 | address, without explicit permission
40 | * Other conduct which could reasonably be considered inappropriate in a
41 | professional setting
42 |
43 | ## Our Responsibilities
44 |
45 | Project maintainers are responsible for clarifying the standards of acceptable
46 | behavior and are expected to take appropriate and fair corrective action in
47 | response to any instances of unacceptable behavior.
48 |
49 | Project maintainers have the right and responsibility to remove, edit, or
50 | reject comments, commits, code, wiki edits, issues, and other contributions
51 | that are not aligned to this Code of Conduct, or to ban temporarily or
52 | permanently any contributor for other behaviors that they deem inappropriate,
53 | threatening, offensive, or harmful.
54 |
55 | ## Scope
56 |
57 | This Code of Conduct applies both within project spaces and in public spaces
58 | when an individual is representing the project or its community. Examples of
59 | representing a project or community include using an official project e-mail
60 | address, posting via an official social media account, or acting as an appointed
61 | representative at an online or offline event. Representation of a project may be
62 | further defined and clarified by project maintainers.
63 |
64 | ## Enforcement
65 |
66 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
67 | reported by contacting the project team at john+github@johnpapa.net. All
68 | complaints will be reviewed and investigated and will result in a response that
69 | is deemed necessary and appropriate to the circumstances. The project team is
70 | obligated to maintain confidentiality with regard to the reporter of an incident.
71 | Further details of specific enforcement policies may be posted separately.
72 |
73 | Project maintainers who do not follow or enforce the Code of Conduct in good
74 | faith may face temporary or permanent repercussions as determined by other
75 | members of the project's leadership.
76 |
77 | ## Attribution
78 |
79 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
80 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
81 |
82 | [homepage]: https://www.contributor-covenant.org
83 |
84 | For answers to common questions about this code of conduct, see
85 | https://www.contributor-covenant.org/faq
86 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | We would love for you to contribute and help make it even better
4 | than it is today! As a contributor, here are the guidelines we would like you
5 | to follow:
6 |
7 | - [Code of Conduct](#coc)
8 |
9 | - [Issues and Bugs](#issue)
10 | - [Feature Requests](#feature)
11 | - [Submission Guidelines](#submit)
12 |
13 | ## Code of Conduct
14 |
15 | Help us keep this project open and inclusive. Please read and follow our [Code of Conduct](./CODE_OF_CONDUCT.md).
16 |
17 | ## Found an Issue?
18 |
19 | If you find a bug in the source code or a mistake in the documentation, you can help us by
20 | [submitting an issue](#submit-issue) to our [GitHub Repository](https://github.com/johnpapa/vscode-peacock). Even better, you can
21 | [submit a Pull Request](#submit-pr) with a fix.
22 |
23 | ## Want a Feature?
24 |
25 | You can _request_ a new feature by [submitting an issue](#submit-issue) to our [GitHub Repository](https://github.com/johnpapa/vscode-peacock). If you would like to _implement_ a new feature, please submit an issue with
26 | a proposal for your work first, to be sure that we can use it.
27 |
28 | - **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr).
29 |
30 | ## Submission Guidelines
31 |
32 | ### Submitting an Issue
33 |
34 | Before you submit an issue, search the archive, maybe your question was already answered.
35 |
36 | If your issue appears to be a bug, and hasn't been reported, open a new issue.
37 | Help us to maximize the effort we can spend fixing issues and adding new
38 | features, by not reporting duplicate issues. Providing the following information will increase the
39 | chances of your issue being dealt with quickly:
40 |
41 | - **Overview of the Issue** - if an error is being thrown a non-minified stack trace helps
42 | - **Version** - what version is affected (e.g. 3.9.0)
43 | - **Motivation for or Use Case** - explain what are you trying to do and why the current behavior is a bug for you
44 | - **Browsers and Operating System** - is this a problem with all browsers?
45 | - **Reproduce the Error** - provide a live example or a unambiguous set of steps
46 | - **Related Issues** - has a similar issue been reported before?
47 | - **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be
48 | causing the problem (line of code or commit)
49 |
50 | You can file new issues by providing the above information [here](https://github.com/johnpapa/vscode-peacock/issues/new).
51 |
52 | ### Submitting a Pull Request (PR)
53 |
54 | Before you submit your Pull Request (PR) consider the following guidelines:
55 |
56 | - Search [GitHub](https://github.com/johnpapa/vscode-peacock/pulls) for an open or closed PR
57 | that relates to your submission. You don't want to duplicate effort.
58 |
59 | - Make your changes in a new git fork.
60 | - Commit your changes using a descriptive commit message.
61 | - Push your fork to GitHub.
62 | - In GitHub, submit a Pull Request.
63 | - If we suggest changes then:
64 | - Make the required updates.
65 | - Rebase your fork and force push to your GitHub repository (this will update your Pull Request):
66 |
67 | ```shell
68 | git rebase main -i
69 | git push -f
70 | ```
71 |
72 | That's it! Thank you for your contribution!
73 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) John Papa.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE
22 |
--------------------------------------------------------------------------------
/azure-pipelines.docs.old.yml:
--------------------------------------------------------------------------------
1 | trigger:
2 | branches:
3 | include:
4 | - main
5 | # wwe only publish docs when we push to main. We shuold have a docs staging site tho.
6 | # pr:
7 | # branches:
8 | # include:
9 | # - '*'
10 | # # must quote since "*" is a YAML reserved character; we want a string
11 |
12 | stages:
13 | - stage: Build_the_Docs
14 | jobs:
15 | - job: Linux
16 | pool:
17 | name: Hosted Ubuntu 1604
18 | demands: npm
19 | strategy:
20 | matrix:
21 | node_12_x:
22 | node_version: 12.x
23 |
24 | steps:
25 | - template: .azure-pipelines/build.docs.yml
26 | - template: .azure-pipelines/create-release.docs.yml
27 |
28 | - stage: Release_the_docs
29 | jobs:
30 | - job: Push_to_Storage
31 | pool:
32 | name: Hosted Ubuntu 1604
33 | strategy:
34 | matrix:
35 | node_12_x:
36 | node_version: 12.x
37 |
38 | steps:
39 | - template: .azure-pipelines/publish-release.docs.yml
40 |
--------------------------------------------------------------------------------
/azure-pipelines.yml:
--------------------------------------------------------------------------------
1 | trigger:
2 | branches:
3 | include:
4 | - main
5 | pr:
6 | branches:
7 | include:
8 | - '*'
9 | # must quote since "*" is a YAML reserved character; we want a string
10 |
11 | stages:
12 | - stage: Build_the_Extension
13 | jobs:
14 | - job: OS_and_Platform
15 | strategy:
16 | matrix:
17 | linux_node_14:
18 | imageName: Hosted Ubuntu 1604
19 | node_version: 14.x
20 | # linux_node_12:
21 | # imageName: Hosted Ubuntu 1604
22 | # node_version: 12.x
23 | mac_node_14:
24 | imageName: Hosted macOS
25 | node_version: 14.x
26 | # mac_node_12:
27 | # imageName: Hosted macOS
28 | # node_version: 12.x
29 | windows_node_14:
30 | imageName: Hosted VS2017
31 | node_version: 14.x
32 | # windows_node_12:
33 | # imageName: Hosted VS2017
34 | # node_version: 12.x
35 | pool:
36 | name: $(imageName)
37 | # pool:
38 | # https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/hosted?view=azure-devops&tabs=yaml#use-a-microsoft-hosted-agent
39 | # name: Hosted Ubuntu 1604
40 | demands: npm
41 |
42 | steps:
43 | - template: .azure-pipelines/build.yml
44 | - template: .azure-pipelines/lint.yml
45 | - template: .azure-pipelines/test.yml
46 | - template: .azure-pipelines/package.yml
47 |
--------------------------------------------------------------------------------
/docs/.vuepress/config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | title: 'Peacock',
3 | lang: 'en-US',
4 | description: 'Coloring your world, one Code editor at a time',
5 | ga: 'your-ga-id',
6 | markdown: {
7 | code: {
8 | lineNumbers: true,
9 | },
10 | },
11 | plugins: [
12 | // require('@vuepress/plugin-google-analytics'),
13 | // {
14 | // ga: 'your-ga-id',
15 | // },
16 | ],
17 | themeConfig: {
18 | search: true,
19 | searchMaxSuggestions: 10,
20 | sidebar: 'auto',
21 | navbar: [
22 | { text: 'Home', link: '/' },
23 | { text: 'Guide', link: '/guide/' },
24 | { text: 'ChangeLog', link: '/changelog/' },
25 | {
26 | text: 'About',
27 | children: [
28 | { text: 'About', link: '/about/history.md' },
29 | { text: 'Code of Conduct', link: '/about/code_of_conduct.md' },
30 | { text: 'Contributing', link: '/about/contributing.md' },
31 | { text: 'License', link: '/about/license.md' },
32 | ],
33 | },
34 | { text: '@john_papa', link: 'https://twitter.com/john_papa' },
35 | ],
36 | logo: '/assets/peacock-icon-small.png',
37 | // Assumes GitHub. Can also be a full GitLab url.
38 | repo: 'johnpapa/vscode-peacock',
39 | // Customising the header label
40 | // Defaults to "GitHub"/"GitLab"/"Bitbucket" depending on `themeConfig.repo`
41 | repoLabel: 'GitHub',
42 |
43 | // Optional options for generating "Edit this page" link
44 |
45 | // if your docs are in a different repo from your main project:
46 | docsRepo: 'johnpapa/vscode-peacock',
47 | // if your docs are not at the root of the repo:
48 | docsDir: 'docs',
49 | // if your docs are in a specific branch (defaults to 'main'):
50 | docsBranch: 'main',
51 | // defaults to false, set to true to enable
52 | editLinks: true,
53 | // custom text for edit link. Defaults to "Edit this page"
54 | editLinkText: 'Help us improve this page!'
55 | },
56 | };
57 |
--------------------------------------------------------------------------------
/docs/.vuepress/dist/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Peacock
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/docs/.vuepress/dist/assets/affected-settings.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnpapa/vscode-peacock/d2c96693dc5c27c9b0271b5ac5b4fd2eef31c5ed/docs/.vuepress/dist/assets/affected-settings.jpg
--------------------------------------------------------------------------------
/docs/.vuepress/dist/assets/element-adjustments.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnpapa/vscode-peacock/d2c96693dc5c27c9b0271b5ac5b4fd2eef31c5ed/docs/.vuepress/dist/assets/element-adjustments.png
--------------------------------------------------------------------------------
/docs/.vuepress/dist/assets/hero.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnpapa/vscode-peacock/d2c96693dc5c27c9b0271b5ac5b4fd2eef31c5ed/docs/.vuepress/dist/assets/hero.png
--------------------------------------------------------------------------------
/docs/.vuepress/dist/assets/img/back-to-top.8b37f773.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/.vuepress/dist/assets/js/491.f3d3f538.js:
--------------------------------------------------------------------------------
1 | "use strict";(self.webpackChunkvscode_peacock=self.webpackChunkvscode_peacock||[]).push([[491],{8491:(e,o,t)=>{t.r(o),t.d(o,{default:()=>h});var l=t(6252),u=t(3577),a=t(2262),n=t(7621),c=t(45);const s={class:"theme-container"},r={class:"theme-default-content"},d=(0,l._)("h1",null,"404",-1),h=(0,l.aZ)({setup(e){var o,t,h;const k=(0,n.I)(),v=(0,c.X6)(),m=null!=(o=v.value.notFound)?o:["Not Found"],p=null!=(t=v.value.home)?t:k.value,f=null!=(h=v.value.backToHome)?h:"Back to home";return(e,o)=>{const t=(0,l.up)("RouterLink");return(0,l.wg)(),(0,l.iD)("div",s,[(0,l._)("div",r,[d,(0,l._)("blockquote",null,(0,u.zw)(m[Math.floor(Math.random()*m.length)]),1),(0,l.Wm)(t,{to:(0,a.SU)(p)},{default:(0,l.w5)((()=>[(0,l.Uk)((0,u.zw)((0,a.SU)(f)),1)])),_:1},8,["to"])])])}}})}}]);
--------------------------------------------------------------------------------
/docs/.vuepress/dist/assets/js/812.5c9465d6.js.LICENSE.txt:
--------------------------------------------------------------------------------
1 | /* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress
2 | * @license MIT */
3 |
4 | /*!
5 | * vue-router v4.0.11
6 | * (c) 2021 Eduardo San Martin Morote
7 | * @license MIT
8 | */
9 |
--------------------------------------------------------------------------------
/docs/.vuepress/dist/assets/js/app.71908e55.js:
--------------------------------------------------------------------------------
1 | "use strict";(self.webpackChunkvscode_peacock=self.webpackChunkvscode_peacock||[]).push([[143],{3131:(e,t,n)=>{n.d(t,{g:()=>i});var o=n(2009),a=n(6971),d=n(1598);const i=[o.Z,a.Z,d.Z]},9947:(e,t,n)=>{n.d(t,{p:()=>o});const o=[n(3051).Z]},4611:(e,t,n)=>{n.d(t,{l:()=>i});var o=n(8866),a=n(1263),d=n(6243);const i=[o.Z,a.Z,d.Z]},4150:(e,t,n)=>{n.d(t,{Z:()=>a});var o=n(6252);const a={404:(0,o.RC)((()=>n.e(491).then(n.bind(n,8491)))),Layout:(0,o.RC)((()=>n.e(293).then(n.bind(n,3293))))}},6056:(e,t,n)=>{n.d(t,{b:()=>a});var o=n(6252);const a={"v-8daa1a0e":(0,o.RC)((()=>n.e(509).then(n.bind(n,1829)))),"v-05b2f426":(0,o.RC)((()=>n.e(726).then(n.bind(n,3052)))),"v-d585fbd8":(0,o.RC)((()=>n.e(999).then(n.bind(n,2848)))),"v-f6faca80":(0,o.RC)((()=>n.e(343).then(n.bind(n,6435)))),"v-5993bf33":(0,o.RC)((()=>n.e(967).then(n.bind(n,7736)))),"v-510ed0d4":(0,o.RC)((()=>n.e(495).then(n.bind(n,1213)))),"v-fffb8e28":(0,o.RC)((()=>n.e(807).then(n.bind(n,9534)))),"v-3706649a":(0,o.RC)((()=>n.e(88).then(n.bind(n,8109))))}},9706:(e,t,n)=>{n.d(t,{T:()=>o});const o={"v-8daa1a0e":()=>n.e(509).then(n.bind(n,6464)).then((({data:e})=>e)),"v-05b2f426":()=>n.e(726).then(n.bind(n,6343)).then((({data:e})=>e)),"v-d585fbd8":()=>n.e(999).then(n.bind(n,9853)).then((({data:e})=>e)),"v-f6faca80":()=>n.e(343).then(n.bind(n,537)).then((({data:e})=>e)),"v-5993bf33":()=>n.e(967).then(n.bind(n,872)).then((({data:e})=>e)),"v-510ed0d4":()=>n.e(495).then(n.bind(n,3707)).then((({data:e})=>e)),"v-fffb8e28":()=>n.e(807).then(n.bind(n,9570)).then((({data:e})=>e)),"v-3706649a":()=>n.e(88).then(n.bind(n,1801)).then((({data:e})=>e))}},4634:(e,t,n)=>{n.d(t,{g:()=>a});var o=n(4802);const a=[["v-8daa1a0e","/","",["/index.html","/README.md"]],["v-05b2f426","/about/code_of_conduct.html","Code of Conduct",["/about/code_of_conduct","/about/code_of_conduct.md"]],["v-d585fbd8","/about/contributing.html","Contributing",["/about/contributing","/about/contributing.md"]],["v-f6faca80","/about/history.html","About",["/about/history","/about/history.md"]],["v-5993bf33","/about/license.html","License",["/about/license","/about/license.md"]],["v-510ed0d4","/changelog/","Changelog",["/changelog/index.html","/changelog/README.md"]],["v-fffb8e28","/guide/","Guide",["/guide/index.html","/guide/README.md"]],["v-3706649a","/404.html","",["/404"]]].reduce(((e,[t,n,a,d])=>(e.push({name:t,path:n,component:o.Y,meta:{title:a}},...d.map((e=>({path:e,redirect:n})))),e)),[{name:"404",path:"/:catchAll(.*)",component:o.Y}])},5220:(e,t,n)=>{n.d(t,{H:()=>o});const o={base:"/",lang:"en-US",title:"Peacock",description:"Coloring your world, one Code editor at a time",head:[],locales:{}}},2232:(e,t,n)=>{n.d(t,{f:()=>o});const o={search:!0,searchMaxSuggestions:10,sidebar:"auto",navbar:[{text:"Home",link:"/"},{text:"Guide",link:"/guide/"},{text:"ChangeLog",link:"/changelog/"},{text:"About",children:[{text:"About",link:"/about/history.md"},{text:"Code of Conduct",link:"/about/code_of_conduct.md"},{text:"Contributing",link:"/about/contributing.md"},{text:"License",link:"/about/license.md"}]},{text:"@john_papa",link:"https://twitter.com/john_papa"}],logo:"/assets/peacock-icon-small.png",repo:"johnpapa/vscode-peacock",repoLabel:"GitHub",docsRepo:"johnpapa/vscode-peacock",docsDir:"docs",docsBranch:"main",editLinks:!0,editLinkText:"Help us improve this page!",locales:{"/":{selectLanguageName:"English"}},darkMode:!0,selectLanguageText:"Languages",selectLanguageAriaLabel:"Select language",sidebarDepth:2,editLink:!0,lastUpdated:!0,lastUpdatedText:"Last Updated",contributors:!0,contributorsText:"Contributors",notFound:["There's nothing here.","How did we get here?","That's a Four-Oh-Four.","Looks like we've got some broken links."],backToHome:"Take me home",openInNewWindow:"open in new window",toggleDarkMode:"toggle dark mode",toggleSidebar:"toggle sidebar"}}},e=>{e.O(0,[460,812],(()=>(5698,e(e.s=5698)))),e.O()}]);
--------------------------------------------------------------------------------
/docs/.vuepress/dist/assets/js/runtime~app.8fcc392a.js:
--------------------------------------------------------------------------------
1 | (()=>{"use strict";var e,r,t,a={},o={};function n(e){var r=o[e];if(void 0!==r)return r.exports;var t=o[e]={exports:{}};return a[e].call(t.exports,t,t.exports,n),t.exports}n.m=a,e=[],n.O=(r,t,a,o)=>{if(!t){var s=1/0;for(l=0;l=o)&&Object.keys(n.O).every((e=>n.O[e](t[d])))?t.splice(d--,1):(i=!1,o0&&e[l-1][2]>o;l--)e[l]=e[l-1];e[l]=[t,a,o]},n.d=(e,r)=>{for(var t in r)n.o(r,t)&&!n.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},n.f={},n.e=e=>Promise.all(Object.keys(n.f).reduce(((r,t)=>(n.f[t](e,r),r)),[])),n.u=e=>"assets/js/"+({88:"v-3706649a",343:"v-f6faca80",495:"v-510ed0d4",509:"v-8daa1a0e",726:"v-05b2f426",807:"v-fffb8e28",967:"v-5993bf33",999:"v-d585fbd8"}[e]||e)+"."+{88:"4fa7f288",293:"bdc27997",343:"3fe5eae0",491:"f3d3f538",495:"fedc348e",509:"c4599b90",726:"62b5ae63",807:"736cfea0",967:"64e26bd3",999:"d7742574"}[e]+".js",n.miniCssF=e=>"assets/css/styles.baa9963c.css",n.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),r={},t="vscode-peacock:",n.l=(e,a,o,s)=>{if(r[e])r[e].push(a);else{var i,d;if(void 0!==o)for(var c=document.getElementsByTagName("script"),l=0;l{i.onerror=i.onload=null,clearTimeout(v);var o=r[e];if(delete r[e],i.parentNode&&i.parentNode.removeChild(i),o&&o.forEach((e=>e(a))),t)return t(a)},v=setTimeout(u.bind(null,void 0,{type:"timeout",target:i}),12e4);i.onerror=u.bind(null,i.onerror),i.onload=u.bind(null,i.onload),d&&document.head.appendChild(i)}},n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.p="/",(()=>{var e={523:0,460:0};n.f.j=(r,t)=>{var a=n.o(e,r)?e[r]:void 0;if(0!==a)if(a)t.push(a[2]);else if(/^(460|523)$/.test(r))e[r]=0;else{var o=new Promise(((t,o)=>a=e[r]=[t,o]));t.push(a[2]=o);var s=n.p+n.u(r),i=new Error;n.l(s,(t=>{if(n.o(e,r)&&(0!==(a=e[r])&&(e[r]=void 0),a)){var o=t&&("load"===t.type?"missing":t.type),s=t&&t.target&&t.target.src;i.message="Loading chunk "+r+" failed.\n("+o+": "+s+")",i.name="ChunkLoadError",i.type=o,i.request=s,a[1](i)}}),"chunk-"+r,r)}},n.O.j=r=>0===e[r];var r=(r,t)=>{var a,o,[s,i,d]=t,c=0;if(s.some((r=>0!==e[r]))){for(a in i)n.o(i,a)&&(n.m[a]=i[a]);if(d)var l=d(n)}for(r&&r(t);c{i.r(t),i.d(t,{data:()=>o});const o={key:"v-05b2f426",path:"/about/code_of_conduct.html",title:"Code of Conduct",lang:"en-US",frontmatter:{title:"Code of Conduct",description:"Code of Conduct guide for the Visual Studio Code Peacock extension",meta:[{name:"keywords"},{content:'vscode "visual studio code" peacock theme extension Code of Conduct'}]},excerpt:"",headers:[{level:2,title:"Our Pledge",slug:"our-pledge",children:[]},{level:2,title:"Our Standards",slug:"our-standards",children:[]},{level:2,title:"Our Responsibilities",slug:"our-responsibilities",children:[]},{level:2,title:"Scope",slug:"scope",children:[]},{level:2,title:"Enforcement",slug:"enforcement",children:[]},{level:2,title:"Attribution",slug:"attribution",children:[]}],filePathRelative:"about/code_of_conduct.md",git:{updatedTime:158994316e4,contributors:[{name:"John Papa",email:"john@johnpapa.net",commits:1}]}}},3052:(e,t,i)=>{i.r(t),i.d(t,{default:()=>p});var o=i(6252);const n=(0,o.uE)(' Contributor Covenant Code of Conduct Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
Our Standards Examples of behavior that contributes to creating a positive environment include:
Using welcoming and inclusive language Being respectful of differing viewpoints and experiences Gracefully accepting constructive criticism Focusing on what is best for the community Showing empathy towards other community members Examples of unacceptable behavior by participants include:
The use of sexualized language or imagery and unwelcome sexual attention or advances Trolling, insulting/derogatory comments, and personal or political attacks Public or private harassment Publishing others' private information, such as a physical or electronic address, without explicit permission Other conduct which could reasonably be considered inappropriate in a professional setting Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at john+github@johnpapa.net. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
Attribution ',17),a=(0,o.Uk)("This Code of Conduct is adapted from the "),r={href:"https://www.contributor-covenant.org",target:"_blank",rel:"noopener noreferrer"},s=(0,o.Uk)("Contributor Covenant"),c=(0,o.Uk)(", version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html"),d=(0,o._)("p",null,"For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq",-1),l={},p=(0,i(3744).Z)(l,[["render",function(e,t){const i=(0,o.up)("OutboundLink");return(0,o.wg)(),(0,o.iD)(o.HY,null,[n,(0,o._)("p",null,[a,(0,o._)("a",r,[s,(0,o.Wm)(i)]),c]),d],64)}]])},3744:(e,t)=>{t.Z=(e,t)=>{for(const[i,o]of t)e[i]=o;return e}}}]);
--------------------------------------------------------------------------------
/docs/.vuepress/dist/assets/js/v-3706649a.4fa7f288.js:
--------------------------------------------------------------------------------
1 | "use strict";(self.webpackChunkvscode_peacock=self.webpackChunkvscode_peacock||[]).push([[88],{1801:(e,t,a)=>{a.r(t),a.d(t,{data:()=>n});const n={key:"v-3706649a",path:"/404.html",title:"",lang:"en-US",frontmatter:{layout:"404"},excerpt:"",headers:[],filePathRelative:null,git:{}}},8109:(e,t,a)=>{a.r(t),a.d(t,{default:()=>c});const n={},c=(0,a(3744).Z)(n,[["render",function(e,t){return null}]])},3744:(e,t)=>{t.Z=(e,t)=>{for(const[a,n]of t)e[a]=n;return e}}}]);
--------------------------------------------------------------------------------
/docs/.vuepress/dist/assets/js/v-5993bf33.64e26bd3.js:
--------------------------------------------------------------------------------
1 | "use strict";(self.webpackChunkvscode_peacock=self.webpackChunkvscode_peacock||[]).push([[967],{872:(e,t,n)=>{n.r(t),n.d(t,{data:()=>o});const o={key:"v-5993bf33",path:"/about/license.html",title:"License",lang:"en-US",frontmatter:{title:"License",description:"License for the Visual Studio Code Peacock extension",meta:[{name:"keywords"},{content:'vscode "visual studio code" peacock theme extension license'}]},excerpt:"",headers:[],filePathRelative:"about/license.md",git:{updatedTime:158994316e4,contributors:[{name:"John Papa",email:"john@johnpapa.net",commits:1}]}}},7736:(e,t,n)=>{n.r(t),n.d(t,{default:()=>a});var o=n(6252);const i=[(0,o._)("code",null,'MIT License\n\nCopyright (c) JohnPapa.net, LLC. All rights reserved.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the "Software"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE\n',-1)],s={},a=(0,n(3744).Z)(s,[["render",function(e,t){return(0,o.wg)(),(0,o.iD)("pre",null,i)}]])},3744:(e,t)=>{t.Z=(e,t)=>{for(const[n,o]of t)e[n]=o;return e}}}]);
--------------------------------------------------------------------------------
/docs/.vuepress/dist/assets/js/v-8daa1a0e.c4599b90.js:
--------------------------------------------------------------------------------
1 | "use strict";(self.webpackChunkvscode_peacock=self.webpackChunkvscode_peacock||[]).push([[509],{6464:(e,t,o)=>{o.r(t),o.d(t,{data:()=>a});const a={key:"v-8daa1a0e",path:"/",title:"",lang:"en-US",frontmatter:{home:!0,heroImage:"assets/hero.png",actions:[{text:"Get Started →",link:"/guide/",type:"primary"}],features:[{title:"Work More Efficiently",details:"Quickly identify each of your Visual Studio Code instances using your favorite colors"},{title:"Remote Integration",details:"Color your Visual Studio Code editor uniquely when you are using the remote integration features."},{title:"Live Share",details:"Color your Visual Studio Code editor uniquely when you are in a Live Share session as a Guest or a Host"}],footer:"MIT Licensed | Copyright © 2019-present John Papa | current version 3.10.0"},excerpt:"",headers:[],filePathRelative:"README.md",git:{updatedTime:1633217573e3,contributors:[{name:"John Papa",email:"john@johnpapa.net",commits:3},{name:"John Papa",email:"johnpapa@users.noreply.github.com",commits:2}]}}},1829:(e,t,o)=>{o.r(t),o.d(t,{default:()=>i});const a={},i=(0,o(3744).Z)(a,[["render",function(e,t){return null}]])},3744:(e,t)=>{t.Z=(e,t)=>{for(const[o,a]of t)e[o]=a;return e}}}]);
--------------------------------------------------------------------------------
/docs/.vuepress/dist/assets/js/v-d585fbd8.d7742574.js:
--------------------------------------------------------------------------------
1 | "use strict";(self.webpackChunkvscode_peacock=self.webpackChunkvscode_peacock||[]).push([[999],{9853:(e,i,t)=>{t.r(i),t.d(i,{data:()=>a});const a={key:"v-d585fbd8",path:"/about/contributing.html",title:"Contributing",lang:"en-US",frontmatter:{title:"Contributing",description:"Conributions guide for the Visual Studio Code Peacock extension",meta:[{name:"keywords"},{content:'vscode "visual studio code" peacock theme extension contributions'}]},excerpt:"",headers:[{level:2,title:"Code of Conduct",slug:"code-of-conduct",children:[]},{level:2,title:"Found an Issue?",slug:"found-an-issue",children:[]},{level:2,title:"Want a Feature?",slug:"want-a-feature",children:[]},{level:2,title:"Submission Guidelines",slug:"submission-guidelines",children:[{level:3,title:"Submitting an Issue",slug:"submitting-an-issue",children:[]},{level:3,title:"Submitting a Pull Request (PR)",slug:"submitting-a-pull-request-pr",children:[]}]}],filePathRelative:"about/contributing.md",git:{updatedTime:158994316e4,contributors:[{name:"John Papa",email:"john@johnpapa.net",commits:1}]}}},2848:(e,i,t)=>{t.r(i),t.d(i,{default:()=>M});var a=t(6252);const n=(0,a.uE)(' Contributing We would love for you to contribute and help make it even better than it is today! As a contributor, here are the guidelines we would like you to follow:
-Code of Conduct
Code of Conduct Help us keep this project open and inclusive.Please read and follow our Code of Conduct .
Found an Issue? ',7),s=(0,a.Uk)("If you find a bug in the source code or a mistake in the documentation, you can help us by "),u=(0,a._)("a",{href:"#submit-issue"},"submitting an issue",-1),o=(0,a.Uk)(" to our "),r={href:"https://github.com/johnpapa/vscode-peacock",target:"_blank",rel:"noopener noreferrer"},l=(0,a.Uk)("GitHub Repository"),d=(0,a.Uk)(". Even better, you can "),c=(0,a._)("a",{href:"#submit-pr"},"submit a Pull Request",-1),h=(0,a.Uk)(" with a fix."),p=(0,a._)("h2",{id:"want-a-feature",tabindex:"-1"},[(0,a._)("a",{class:"header-anchor",href:"#want-a-feature","aria-hidden":"true"},"#"),(0,a.Uk)(),(0,a._)("a",{name:"feature"}),(0,a.Uk)(" Want a Feature?")],-1),b=(0,a.Uk)("You can "),f=(0,a._)("em",null,"request",-1),g=(0,a.Uk)(" a new feature by "),m=(0,a._)("a",{href:"#submit-issue"},"submitting an issue",-1),k=(0,a.Uk)(" to our "),y={href:"https://github.com/johnpapa/vscode-peacock",target:"_blank",rel:"noopener noreferrer"},w=(0,a.Uk)("GitHub Repository"),v=(0,a.Uk)(".If you would like to "),_=(0,a._)("em",null,"implement",-1),U=(0,a.Uk)(" a new feature, please submit an issue with a proposal for your work first, to be sure that we can use it."),x=(0,a.uE)(' Submission Guidelines Submitting an Issue Before you submit an issue, search the archive, maybe your question was already answered.
If your issue appears to be a bug, and hasn't been reported, open a new issue. Help us to maximize the effort we can spend fixing issues and adding new features, by not reporting duplicate issues.Providing the following information will increase the chances of your issue being dealt with quickly:
Overview of the Issue - if an error is being thrown a non- minified stack trace helps Version - what version is affected (e.g. 0.1.2) Motivation for or Use Case - explain what are you trying to do and why the current behavior is a bug for you Browsers and Operating System - is this a problem with all browsers?Reproduce the Error - provide a live example or a unambiguous set of steps Related Issues - has a similar issue been reported before?Suggest a Fix - if you can't fix the bug yourself, perhaps you can point to what might be causing the problem (line of code or commit) ',6),C=(0,a.Uk)("You can file new issues by providing the above information "),R={href:"https://github.com/johnpapa/vscode-peacock/issues/new",target:"_blank",rel:"noopener noreferrer"},P=(0,a.Uk)("here"),q=(0,a.Uk)("."),S=(0,a._)("h3",{id:"submitting-a-pull-request-pr",tabindex:"-1"},[(0,a._)("a",{class:"header-anchor",href:"#submitting-a-pull-request-pr","aria-hidden":"true"},"#"),(0,a.Uk)(),(0,a._)("a",{name:"submit-pr"}),(0,a.Uk)(" Submitting a Pull Request (PR)")],-1),I=(0,a._)("p",null,"Before you submit your Pull Request (PR) consider the following guidelines:",-1),G=(0,a.Uk)("Search "),H={href:"https://github.com/johnpapa/vscode-peacock/pulls",target:"_blank",rel:"noopener noreferrer"},j=(0,a.Uk)("GitHub"),F=(0,a.Uk)(" for an open or closed PR that relates to your submission.You don't want to duplicate effort."),W=(0,a._)("ul",null,[(0,a._)("li",null,"Make your changes in a new git fork:")],-1),E=(0,a.uE)('Commit your changes using a descriptive commit message
Push your fork to GitHub: In GitHub, send a pull request
If we suggest changes then:
Make the required updates.
Rebase your fork and force push to your GitHub repository (this will update your Pull Request):
git rebase master -i\ngit push -f\n
1 2
',2),B=(0,a._)("p",null,"That's it! Thank you for your contribution!",-1),Y={},M=(0,t(3744).Z)(Y,[["render",function(e,i){const t=(0,a.up)("OutboundLink");return(0,a.wg)(),(0,a.iD)(a.HY,null,[n,(0,a._)("p",null,[s,u,o,(0,a._)("a",r,[l,(0,a.Wm)(t)]),d,c,h]),p,(0,a._)("p",null,[b,f,g,m,k,(0,a._)("a",y,[w,(0,a.Wm)(t)]),v,_,U]),x,(0,a._)("p",null,[C,(0,a._)("a",R,[P,(0,a.Wm)(t)]),q]),S,I,(0,a._)("ul",null,[(0,a._)("li",null,[(0,a._)("p",null,[G,(0,a._)("a",H,[j,(0,a.Wm)(t)]),F]),W]),E]),B],64)}]])},3744:(e,i)=>{i.Z=(e,i)=>{for(const[t,a]of i)e[t]=a;return e}}}]);
--------------------------------------------------------------------------------
/docs/.vuepress/dist/assets/js/v-f6faca80.3fe5eae0.js:
--------------------------------------------------------------------------------
1 | "use strict";(self.webpackChunkvscode_peacock=self.webpackChunkvscode_peacock||[]).push([[343],{537:(e,t,o)=>{o.r(t),o.d(t,{data:()=>a});const a={key:"v-f6faca80",path:"/about/history.html",title:"About",lang:"en-US",frontmatter:{title:"About",description:"About the Visual Studio Code and the Peacock Extension",meta:[{name:"keywords"},{content:'vscode "visual studio code" peacock theme extension'}]},excerpt:"",headers:[{level:2,title:"Why Peacock",slug:"why-peacock",children:[]},{level:2,title:"History of Peacock",slug:"history-of-peacock",children:[]}],filePathRelative:"about/history.md",git:{updatedTime:158994316e4,contributors:[{name:"John Papa",email:"john@johnpapa.net",commits:1}]}}},6435:(e,t,o)=>{o.r(t),o.d(t,{default:()=>W});var a=o(6252);const i=(0,a._)("h1",{id:"about-peacock",tabindex:"-1"},[(0,a._)("a",{class:"header-anchor",href:"#about-peacock","aria-hidden":"true"},"#"),(0,a.Uk)(" About Peacock")],-1),n=(0,a._)("p",null,"Subtly change the color of your Visual Studio (VS) Code workspace. Ideal when you have multiple VS Code instances, use Visual Studio Live Share, or use VS Code's Remote features, and you want to quickly identify your editor.",-1),c=(0,a._)("h2",{id:"why-peacock",tabindex:"-1"},[(0,a._)("a",{class:"header-anchor",href:"#why-peacock","aria-hidden":"true"},"#"),(0,a.Uk)(" Why Peacock")],-1),r=(0,a._)("p",null,"Have you ever found yourself switching between multiple instances of VS Code, while trying to find which one you were looking for? I often have multiple instances open for coding, writing, and pretty much everything I do with text. Being able to quickly identify each instance is super helpful.",-1),s=(0,a.Uk)("I used to switch the colors of a few key aspects of VS Code manually so I could differentiate them. I was using this technique at conferences where I presented and found it helpful for the audience so they could identify my code too. I finally decided to automate this. That's where "),d={href:"https://marketplace.visualstudio.com/items?itemName=johnpapa.vscode-peacock&wt.mc_id=vscodepeacock-github-jopapa",target:"_blank",rel:"noopener noreferrer"},h=(0,a.Uk)("Peacock"),l=(0,a.Uk)(" came from."),u=(0,a._)("h2",{id:"history-of-peacock",tabindex:"-1"},[(0,a._)("a",{class:"header-anchor",href:"#history-of-peacock","aria-hidden":"true"},"#"),(0,a.Uk)(" History of Peacock")],-1),p=(0,a.Uk)("A while back I created a theme for "),m={href:"https://code.visualstudio.com?wt.mc_id=vscodepeacock-github-jopapa",target:"_blank",rel:"noopener noreferrer"},k=(0,a.Uk)("Visual Studio Code"),f=(0,a.Uk)(" called "),y={href:"https://marketplace.visualstudio.com/items?itemName=johnpapa.winteriscoming&wt.mc_id=vscodepeacock-github-jopapa",target:"_blank",rel:"noopener noreferrer"},w=(0,a.Uk)("Winter is Coming"),g=(0,a.Uk)(". I learned how to do this by reading this "),b={href:"https://code.visualstudio.com/api/extension-capabilities/theming?wt.mc_id=vscodepeacock-github-jopapa",target:"_blank",rel:"noopener noreferrer"},v=(0,a.Uk)("great guide on theming"),_=(0,a.Uk)(" in the VS Code docs. I still use it today (I love the dark versions). It taught me a lot about how to customize colors in VS Code."),I=(0,a._)("p",null,"I then started using this to help solve another problem I had - quickly and visually differentiating between VS Code instances",-1),U=(0,a._)("p",null,"I'm often working on multiple code projects an articles I am writing in markdown. My workflow is to open different separate VS Code instances for each, as they are often unrelated to each other. As my mind shifts between the work, I find myself cycling through the instances and it takes me a bit of time to identify which instance I want to in focus.",-1),S=(0,a._)("p",null,"I decided to automate this. Once I had a working extension completed, I created a simple animated gif and shared it on twitter to see if anyone else was interested. Then I went to bed. I woke up he next morning to a lot of positive reactions than from the community (thank you). I also received many great contributions already (thank you again!).",-1),C=(0,a.Uk)("If you are interested in trying out Peacock, you can "),V={href:"https://marketplace.visualstudio.com/items?itemName=johnpapa.vscode-peacock&wt.mc_id=vscodepeacock-github-jopapa",target:"_blank",rel:"noopener noreferrer"},j=(0,a.Uk)("find it here in the marketplace"),x=(0,a.Uk)("."),P={},W=(0,o(3744).Z)(P,[["render",function(e,t){const o=(0,a.up)("OutboundLink");return(0,a.wg)(),(0,a.iD)(a.HY,null,[i,n,c,r,(0,a._)("p",null,[s,(0,a._)("a",d,[h,(0,a.Wm)(o)]),l]),u,(0,a._)("p",null,[p,(0,a._)("a",m,[k,(0,a.Wm)(o)]),f,(0,a._)("a",y,[w,(0,a.Wm)(o)]),g,(0,a._)("a",b,[v,(0,a.Wm)(o)]),_]),I,U,S,(0,a._)("p",null,[C,(0,a._)("a",V,[j,(0,a.Wm)(o)]),x])],64)}]])},3744:(e,t)=>{t.Z=(e,t)=>{for(const[o,a]of t)e[o]=a;return e}}}]);
--------------------------------------------------------------------------------
/docs/.vuepress/dist/assets/named-colors.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnpapa/vscode-peacock/d2c96693dc5c27c9b0271b5ac5b4fd2eef31c5ed/docs/.vuepress/dist/assets/named-colors.gif
--------------------------------------------------------------------------------
/docs/.vuepress/dist/assets/peacock-3-instances.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnpapa/vscode-peacock/d2c96693dc5c27c9b0271b5ac5b4fd2eef31c5ed/docs/.vuepress/dist/assets/peacock-3-instances.gif
--------------------------------------------------------------------------------
/docs/.vuepress/dist/assets/peacock-icon-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnpapa/vscode-peacock/d2c96693dc5c27c9b0271b5ac5b4fd2eef31c5ed/docs/.vuepress/dist/assets/peacock-icon-small.png
--------------------------------------------------------------------------------
/docs/.vuepress/dist/assets/peacock-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnpapa/vscode-peacock/d2c96693dc5c27c9b0271b5ac5b4fd2eef31c5ed/docs/.vuepress/dist/assets/peacock-icon.png
--------------------------------------------------------------------------------
/docs/.vuepress/dist/assets/peacock-live-share-demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnpapa/vscode-peacock/d2c96693dc5c27c9b0271b5ac5b4fd2eef31c5ed/docs/.vuepress/dist/assets/peacock-live-share-demo.gif
--------------------------------------------------------------------------------
/docs/.vuepress/dist/assets/peacock-remote.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnpapa/vscode-peacock/d2c96693dc5c27c9b0271b5ac5b4fd2eef31c5ed/docs/.vuepress/dist/assets/peacock-remote.gif
--------------------------------------------------------------------------------
/docs/.vuepress/dist/assets/peacock-sketchnote.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnpapa/vscode-peacock/d2c96693dc5c27c9b0271b5ac5b4fd2eef31c5ed/docs/.vuepress/dist/assets/peacock-sketchnote.png
--------------------------------------------------------------------------------
/docs/.vuepress/dist/assets/peacock-windows.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnpapa/vscode-peacock/d2c96693dc5c27c9b0271b5ac5b4fd2eef31c5ed/docs/.vuepress/dist/assets/peacock-windows.png
--------------------------------------------------------------------------------
/docs/.vuepress/dist/assets/title-bar-coloring-settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnpapa/vscode-peacock/d2c96693dc5c27c9b0271b5ac5b4fd2eef31c5ed/docs/.vuepress/dist/assets/title-bar-coloring-settings.png
--------------------------------------------------------------------------------
/docs/.vuepress/public/assets/affected-settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnpapa/vscode-peacock/d2c96693dc5c27c9b0271b5ac5b4fd2eef31c5ed/docs/.vuepress/public/assets/affected-settings.png
--------------------------------------------------------------------------------
/docs/.vuepress/public/assets/element-adjustments.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnpapa/vscode-peacock/d2c96693dc5c27c9b0271b5ac5b4fd2eef31c5ed/docs/.vuepress/public/assets/element-adjustments.png
--------------------------------------------------------------------------------
/docs/.vuepress/public/assets/hero.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnpapa/vscode-peacock/d2c96693dc5c27c9b0271b5ac5b4fd2eef31c5ed/docs/.vuepress/public/assets/hero.png
--------------------------------------------------------------------------------
/docs/.vuepress/public/assets/named-colors.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnpapa/vscode-peacock/d2c96693dc5c27c9b0271b5ac5b4fd2eef31c5ed/docs/.vuepress/public/assets/named-colors.gif
--------------------------------------------------------------------------------
/docs/.vuepress/public/assets/peacock-3-instances.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnpapa/vscode-peacock/d2c96693dc5c27c9b0271b5ac5b4fd2eef31c5ed/docs/.vuepress/public/assets/peacock-3-instances.gif
--------------------------------------------------------------------------------
/docs/.vuepress/public/assets/peacock-icon-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnpapa/vscode-peacock/d2c96693dc5c27c9b0271b5ac5b4fd2eef31c5ed/docs/.vuepress/public/assets/peacock-icon-small.png
--------------------------------------------------------------------------------
/docs/.vuepress/public/assets/peacock-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnpapa/vscode-peacock/d2c96693dc5c27c9b0271b5ac5b4fd2eef31c5ed/docs/.vuepress/public/assets/peacock-icon.png
--------------------------------------------------------------------------------
/docs/.vuepress/public/assets/peacock-live-share-demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnpapa/vscode-peacock/d2c96693dc5c27c9b0271b5ac5b4fd2eef31c5ed/docs/.vuepress/public/assets/peacock-live-share-demo.gif
--------------------------------------------------------------------------------
/docs/.vuepress/public/assets/peacock-remote.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnpapa/vscode-peacock/d2c96693dc5c27c9b0271b5ac5b4fd2eef31c5ed/docs/.vuepress/public/assets/peacock-remote.gif
--------------------------------------------------------------------------------
/docs/.vuepress/public/assets/peacock-sketchnote.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnpapa/vscode-peacock/d2c96693dc5c27c9b0271b5ac5b4fd2eef31c5ed/docs/.vuepress/public/assets/peacock-sketchnote.png
--------------------------------------------------------------------------------
/docs/.vuepress/public/assets/peacock-windows.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnpapa/vscode-peacock/d2c96693dc5c27c9b0271b5ac5b4fd2eef31c5ed/docs/.vuepress/public/assets/peacock-windows.png
--------------------------------------------------------------------------------
/docs/.vuepress/public/assets/title-bar-coloring-settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnpapa/vscode-peacock/d2c96693dc5c27c9b0271b5ac5b4fd2eef31c5ed/docs/.vuepress/public/assets/title-bar-coloring-settings.png
--------------------------------------------------------------------------------
/docs/.vuepress/styles/index.scss:
--------------------------------------------------------------------------------
1 | :root {
2 | // brand colors
3 | --c-brand: #00b3e6;
4 | --c-brand-light: #65ceff;
5 |
6 | // background colors
7 | --c-bg: #ffffff;
8 | --c-bg-light: #f3f4f5;
9 | --c-bg-lighter: #eeeeee;
10 | --c-bg-navbar: var(--c-bg);
11 | --c-bg-sidebar: var(--c-bg);
12 | --c-bg-arrow: #cccccc;
13 |
14 | // text colors
15 | --c-text: #2c3e50;
16 | --c-text-accent: var(--c-brand);
17 | --c-text-light: #3a5169;
18 | --c-text-lighter: #4e6e8e;
19 | --c-text-lightest: #6a8bad;
20 | --c-text-quote: #999999;
21 |
22 | // border colors
23 | --c-border: #eaecef;
24 | --c-border-dark: #dfe2e5;
25 |
26 | // custom container colors
27 | --c-tip: #00b3e6;
28 | --c-tip-bg: var(--c-bg-light);
29 | --c-tip-title: var(--c-text);
30 | --c-tip-text: var(--c-text);
31 | --c-tip-text-accent: var(--c-text-accent);
32 | --c-warning: #e7c000;
33 | --c-warning-bg: #fffae3;
34 | --c-warning-title: #ad9000;
35 | --c-warning-text: #746000;
36 | --c-warning-text-accent: var(--c-text);
37 | --c-danger: #cc0000;
38 | --c-danger-bg: #ffe0e0;
39 | --c-danger-title: #990000;
40 | --c-danger-text: #660000;
41 | --c-danger-text-accent: var(--c-text);
42 | --c-details-bg: #eeeeee;
43 |
44 | // badge component colors
45 | --c-badge-tip: var(--c-tip);
46 | --c-badge-warning: var(--c-warning);
47 | --c-badge-danger: var(--c-danger);
48 |
49 | // transition vars
50 | --t-color: 0.3s ease;
51 | --t-transform: 0.3s ease;
52 |
53 | // code blocks vars
54 | --code-bg-color: #282c34;
55 | --code-hl-bg-color: rgba(0, 0, 0, 0.66);
56 | --code-ln-color: #9e9e9e;
57 | --code-ln-wrapper-width: 3.5rem;
58 |
59 | // font vars
60 | --font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell,
61 | 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
62 | --font-family-code: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
63 |
64 | // layout vars
65 | --navbar-height: 3.6rem;
66 | --navbar-padding-v: 0.7rem;
67 | --navbar-padding-h: 1.5rem;
68 | --sidebar-width: 20rem;
69 | --sidebar-width-mobile: calc(var(--sidebar-width) * 0.82);
70 | --content-width: 740px;
71 | --homepage-width: 960px;
72 | }
73 |
74 | // plugin-back-to-top
75 | .back-to-top {
76 | --back-to-top-color: var(--c-brand);
77 | --back-to-top-color-hover: var(--c-brand-light);
78 | }
79 |
80 | // plugin-docsearch
81 | .DocSearch {
82 | --docsearch-primary-color: var(--c-brand);
83 | --docsearch-text-color: var(--c-text);
84 | --docsearch-highlight-color: var(--c-brand);
85 | --docsearch-muted-color: var(--c-text-quote);
86 | --docsearch-container-background: rgba(9, 10, 17, 0.8);
87 | --docsearch-modal-background: var(--c-bg-light);
88 | --docsearch-searchbox-background: var(--c-bg-lighter);
89 | --docsearch-searchbox-focus-background: var(--c-bg);
90 | --docsearch-searchbox-shadow: inset 0 0 0 2px var(--c-brand);
91 | --docsearch-hit-color: var(--c-text-light);
92 | --docsearch-hit-active-color: var(--c-bg);
93 | --docsearch-hit-background: var(--c-bg);
94 | --docsearch-hit-shadow: 0 1px 3px 0 var(--c-border-dark);
95 | --docsearch-footer-background: var(--c-bg);
96 | }
97 |
98 | // plugin-medium-zoom
99 | .medium-zoom-overlay {
100 | --medium-zoom-bg-color: var(--c-bg);
101 | }
102 |
103 | // plugin-nprogress
104 | #nprogress {
105 | --nprogress-color: var(--c-brand);
106 | }
107 |
108 | // plugin-pwa-popup
109 | .pwa-popup {
110 | --pwa-popup-text-color: var(--c-text);
111 | --pwa-popup-bg-color: var(--c-bg);
112 | --pwa-popup-border-color: var(--c-brand);
113 | --pwa-popup-shadow: 0 4px 16px var(--c-brand);
114 | --pwa-popup-btn-text-color: var(--c-bg);
115 | --pwa-popup-btn-bg-color: var(--c-brand);
116 | --pwa-popup-btn-hover-bg-color: var(--c-brand-light);
117 | }
118 |
119 | // plugin-search
120 | .search-box {
121 | --search-bg-color: var(--c-bg);
122 | --search-accent-color: var(--c-brand);
123 | --search-text-color: var(--c-text);
124 | --search-border-color: var(--c-border);
125 |
126 | --search-item-text-color: var(--c-text-lighter);
127 | --search-item-focus-bg-color: var(--c-bg-light);
128 | }
129 |
130 | html.dark {
131 | // brand colors
132 | --c-brand: #00b3e6;
133 | --c-brand-light: #65ceff;
134 |
135 | // background colors
136 | --c-bg: #22272e;
137 | --c-bg-light: #2b313a;
138 | --c-bg-lighter: #262c34;
139 |
140 | // text colors
141 | --c-text: #adbac7;
142 | --c-text-light: #96a7b7;
143 | --c-text-lighter: #8b9eb0;
144 | --c-text-lightest: #8094a8;
145 |
146 | // border colors
147 | --c-border: #3e4c5a;
148 | --c-border-dark: #34404c;
149 |
150 | // custom container colors
151 | --c-tip: #318a62;
152 | --c-warning: #ceab00;
153 | --c-warning-bg: #7e755b;
154 | --c-warning-title: #ceac03;
155 | --c-warning-text: #362e00;
156 | --c-danger: #940000;
157 | --c-danger-bg: #806161;
158 | --c-danger-title: #610000;
159 | --c-danger-text: #3a0000;
160 | --c-details-bg: #323843;
161 |
162 | // code blocks vars
163 | --code-hl-bg-color: #363b46;
164 | }
165 |
166 | // plugin-docsearch
167 | html.dark .DocSearch {
168 | --docsearch-logo-color: var(--c-text);
169 | --docsearch-modal-shadow: inset 1px 1px 0 0 #2c2e40, 0 3px 8px 0 #000309;
170 | --docsearch-key-shadow: inset 0 -2px 0 0 #282d55, inset 0 0 1px 1px #51577d,
171 | 0 2px 2px 0 rgba(3, 4, 9, 0.3);
172 | --docsearch-key-gradient: linear-gradient(-225deg, #444950, #1c1e21);
173 | --docsearch-footer-shadow: inset 0 1px 0 0 rgba(73, 76, 106, 0.5), 0 -4px 8px 0 rgba(0, 0, 0, 0.2);
174 | }
175 |
--------------------------------------------------------------------------------
/docs/.vuepress/styles/palette.scss:
--------------------------------------------------------------------------------
1 | $accentColor: #00b3e6;
2 | $hoverColor: #00b3e6;
3 | $textColor: #111;
4 | $borderColor: #00b3e6;
5 | $borderAccentColor: #00b3e6;
6 | $codeBgColor: #011627;
7 | $arrowBgColor: #00b3e6;
8 |
9 | //2c3e50
10 |
11 | header.navbar,
12 | header.navbar .links,
13 | header.navbar .search-box {
14 | border-bottom: $borderColor 1px solid;
15 | }
16 |
17 | span.site-name.can-hide,
18 | .nav-item,
19 | a.repo-link,
20 | a.nav-link,
21 | a.nav-link.router-link-active {
22 | svg.icon.outbound {
23 | &:hover {
24 | color: $hoverColor;
25 | }
26 | }
27 | }
28 | a.nav-link {
29 | &:hover {
30 | color: $hoverColor;
31 | }
32 | }
33 |
34 | .page .theme-default-content:not(.custom),
35 | .page .theme-default-content {
36 | h2,
37 | h3,
38 | h4 {
39 | border-left: 16px solid $borderColor;
40 | border-bottom: 1px solid $borderColor;
41 | padding: 2px 16px 6px 8px;
42 | a.header-anchor {
43 | padding-left: 16px;
44 | }
45 | margin-top: 48px;
46 | }
47 | h3 {
48 | border-left: 8px solid $borderColor;
49 | padding-left: 8px;
50 | }
51 | h4 {
52 | border-left: 4px solid $borderColor;
53 | padding-left: 0;
54 | }
55 | }
56 |
57 | .sidebar-link.active {
58 | border-left: 8px $accentColor solid;
59 | }
60 | .sidebar-sub-headers a.sidebar-link {
61 | border-left: none;
62 | }
63 |
64 | .theme-default-content code {
65 | background-color: #00b3e622 !important;
66 | letter-spacing: 2px;
67 | }
68 |
69 | td {
70 | line-height: 22px;
71 | }
72 |
73 | .line-number {
74 | color: $accentColor;
75 | }
76 |
77 | @media (max-width: 719px) {
78 | .sidebar {
79 | .nav-links {
80 | span.site-name.can-hide,
81 | .nav-item,
82 | a.repo-link,
83 | a.nav-link,
84 | a.nav-link.router-link-active,
85 | svg.icon.outbound {
86 | color: $textColor;
87 | // &:hover {
88 | // color: $hoverColor;
89 | // }
90 | }
91 | }
92 | }
93 |
94 | .page-edit .edit-link a {
95 | color: #777;
96 | &::before {
97 | content: '{ ';
98 | }
99 | &::after {
100 | content: ' }';
101 | }
102 | // &:hover {
103 | // color: $hoverColor;
104 | // }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | home: true
3 | heroImage: assets/hero.png
4 | actions:
5 | - text: Get Started →
6 | link: /guide/
7 | type: primary
8 | features:
9 | - title: Work More Efficiently
10 | details: Quickly identify each of your Visual Studio Code instances using your favorite colors
11 | - title: Remote Integration
12 | details: Color your Visual Studio Code editor uniquely when you are using the remote integration features.
13 | - title: Live Share
14 | details: Color your Visual Studio Code editor uniquely when you are in a Live Share session as a Guest or a Host
15 | footer: MIT Licensed | Copyright © 2019-present John Papa | current version 4.2.3
16 | ---
17 |
--------------------------------------------------------------------------------
/docs/about/code_of_conduct.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Code of Conduct
3 | # We can even add meta tags to the page! This sets the keywords meta tag.
4 | #
5 | description: Code of Conduct guide for the Visual Studio Code Peacock extension
6 | meta:
7 | - name: keywords
8 | - content: vscode "visual studio code" peacock theme extension Code of Conduct
9 | ---
10 | # Contributor Covenant Code of Conduct
11 |
12 | ## Our Pledge
13 |
14 | In the interest of fostering an open and welcoming environment, we as
15 | contributors and maintainers pledge to making participation in our project and
16 | our community a harassment-free experience for everyone, regardless of age, body
17 | size, disability, ethnicity, sex characteristics, gender identity and expression,
18 | level of experience, education, socio-economic status, nationality, personal
19 | appearance, race, religion, or sexual identity and orientation.
20 |
21 | ## Our Standards
22 |
23 | Examples of behavior that contributes to creating a positive environment
24 | include:
25 |
26 | * Using welcoming and inclusive language
27 | * Being respectful of differing viewpoints and experiences
28 | * Gracefully accepting constructive criticism
29 | * Focusing on what is best for the community
30 | * Showing empathy towards other community members
31 |
32 | Examples of unacceptable behavior by participants include:
33 |
34 | * The use of sexualized language or imagery and unwelcome sexual attention or
35 | advances
36 | * Trolling, insulting/derogatory comments, and personal or political attacks
37 | * Public or private harassment
38 | * Publishing others' private information, such as a physical or electronic
39 | address, without explicit permission
40 | * Other conduct which could reasonably be considered inappropriate in a
41 | professional setting
42 |
43 | ## Our Responsibilities
44 |
45 | Project maintainers are responsible for clarifying the standards of acceptable
46 | behavior and are expected to take appropriate and fair corrective action in
47 | response to any instances of unacceptable behavior.
48 |
49 | Project maintainers have the right and responsibility to remove, edit, or
50 | reject comments, commits, code, wiki edits, issues, and other contributions
51 | that are not aligned to this Code of Conduct, or to ban temporarily or
52 | permanently any contributor for other behaviors that they deem inappropriate,
53 | threatening, offensive, or harmful.
54 |
55 | ## Scope
56 |
57 | This Code of Conduct applies both within project spaces and in public spaces
58 | when an individual is representing the project or its community. Examples of
59 | representing a project or community include using an official project e-mail
60 | address, posting via an official social media account, or acting as an appointed
61 | representative at an online or offline event. Representation of a project may be
62 | further defined and clarified by project maintainers.
63 |
64 | ## Enforcement
65 |
66 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
67 | reported by contacting the project team at john+github@johnpapa.net. All
68 | complaints will be reviewed and investigated and will result in a response that
69 | is deemed necessary and appropriate to the circumstances. The project team is
70 | obligated to maintain confidentiality with regard to the reporter of an incident.
71 | Further details of specific enforcement policies may be posted separately.
72 |
73 | Project maintainers who do not follow or enforce the Code of Conduct in good
74 | faith may face temporary or permanent repercussions as determined by other
75 | members of the project's leadership.
76 |
77 | ## Attribution
78 |
79 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
80 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
81 |
82 | [homepage]: https://www.contributor-covenant.org
83 |
84 | For answers to common questions about this code of conduct, see
85 | https://www.contributor-covenant.org/faq
86 |
--------------------------------------------------------------------------------
/docs/about/contributing.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Contributing
3 | # We can even add meta tags to the page! This sets the keywords meta tag.
4 | #
5 | description: Conributions guide for the Visual Studio Code Peacock extension
6 | meta:
7 | - name: keywords
8 | - content: vscode "visual studio code" peacock theme extension contributions
9 | ---
10 |
11 | # Contributing
12 |
13 | We would love for you to contribute and help make it even better
14 | than it is today! As a contributor, here are the guidelines we would like you
15 | to follow:
16 |
17 | -[Code of Conduct](#coc)
18 |
19 | - [Issues and Bugs](#issue)
20 | - [Feature Requests](#feature)
21 | - [Submission Guidelines](#submit)
22 |
23 | ## Code of Conduct
24 |
25 | Help us keep this project open and inclusive.Please read and follow our [Code of Conduct](./code_of_conduct).
26 |
27 | ## Found an Issue?
28 |
29 | If you find a bug in the source code or a mistake in the documentation, you can help us by
30 | [submitting an issue](#submit-issue) to our [GitHub Repository](https://github.com/johnpapa/vscode-peacock). Even better, you can
31 | [submit a Pull Request](#submit-pr) with a fix.
32 |
33 | ## Want a Feature?
34 |
35 | You can _request_ a new feature by [submitting an issue](#submit-issue) to our [GitHub Repository](https://github.com/johnpapa/vscode-peacock).If you would like to _implement_ a new feature, please submit an issue with
36 | a proposal for your work first, to be sure that we can use it.
37 |
38 | - **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr).
39 |
40 | ## Submission Guidelines
41 |
42 | ### Submitting an Issue
43 |
44 | Before you submit an issue, search the archive, maybe your question was already answered.
45 |
46 | If your issue appears to be a bug, and hasn't been reported, open a new issue.
47 | Help us to maximize the effort we can spend fixing issues and adding new
48 | features, by not reporting duplicate issues.Providing the following information will increase the
49 | chances of your issue being dealt with quickly:
50 |
51 | - **Overview of the Issue** - if an error is being thrown a non- minified stack trace helps
52 | - **Version** - what version is affected (e.g. 0.1.2)
53 | - **Motivation for or Use Case** - explain what are you trying to do and why the current behavior is a bug for you
54 | - **Browsers and Operating System** - is this a problem with all browsers?
55 | - **Reproduce the Error** - provide a live example or a unambiguous set of steps
56 | - **Related Issues** - has a similar issue been reported before?
57 | - **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be
58 | causing the problem (line of code or commit)
59 |
60 | You can file new issues by providing the above information [here](https://github.com/johnpapa/vscode-peacock/issues/new).
61 |
62 | ### Submitting a Pull Request (PR)
63 |
64 | Before you submit your Pull Request (PR) consider the following guidelines:
65 |
66 | - Search [GitHub](https://github.com/johnpapa/vscode-peacock/pulls) for an open or closed PR
67 | that relates to your submission.You don't want to duplicate effort.
68 |
69 | - Make your changes in a new git fork:
70 |
71 | - Commit your changes using a descriptive commit message
72 | - Push your fork to GitHub:
73 | - In GitHub, send a pull request
74 |
75 | - If we suggest changes then:
76 | - Make the required updates.
77 | - Rebase your fork and force push to your GitHub repository (this will update your Pull Request):
78 |
79 | ```shell
80 | git rebase master -i
81 | git push -f
82 | ```
83 |
84 | That's it! Thank you for your contribution!
85 |
--------------------------------------------------------------------------------
/docs/about/history.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: About
3 | # We can even add meta tags to the page! This sets the keywords meta tag.
4 | #
5 | description: About the Visual Studio Code and the Peacock Extension
6 | meta:
7 | - name: keywords
8 | - content: vscode "visual studio code" peacock theme extension
9 | ---
10 |
11 | # About Peacock
12 |
13 | Subtly change the color of your Visual Studio (VS) Code workspace. Ideal when you have multiple VS Code instances, use Visual Studio Live Share, or use VS Code's Remote features, and you want to quickly identify your editor.
14 |
15 | ## Why Peacock
16 |
17 | Have you ever found yourself switching between multiple instances of VS Code, while trying to find which one you were looking for? I often have multiple instances open for coding, writing, and pretty much everything I do with text. Being able to quickly identify each instance is super helpful.
18 |
19 | I used to switch the colors of a few key aspects of VS Code manually so I could differentiate them. I was using this technique at conferences where I presented and found it helpful for the audience so they could identify my code too. I finally decided to automate this. That's where [Peacock](https://marketplace.visualstudio.com/items?itemName=johnpapa.vscode-peacock&wt.mc_id=vscodepeacock-github-jopapa) came from.
20 |
21 | ## History of Peacock
22 |
23 | A while back I created a theme for [Visual Studio Code](https://code.visualstudio.com?wt.mc_id=vscodepeacock-github-jopapa) called [Winter is Coming](https://marketplace.visualstudio.com/items?itemName=johnpapa.winteriscoming&wt.mc_id=vscodepeacock-github-jopapa). I learned how to do this by reading this [great guide on theming](https://code.visualstudio.com/api/extension-capabilities/theming?wt.mc_id=vscodepeacock-github-jopapa) in the VS Code docs. I still use it today (I love the dark versions). It taught me a lot about how to customize colors in VS Code.
24 |
25 | I then started using this to help solve another problem I had - quickly and visually differentiating between VS Code instances
26 |
27 | I'm often working on multiple code projects an articles I am writing in markdown. My workflow is to open different separate VS Code instances for each, as they are often unrelated to each other. As my mind shifts between the work, I find myself cycling through the instances and it takes me a bit of time to identify which instance I want to in focus.
28 |
29 | I decided to automate this. Once I had a working extension completed, I created a simple animated gif and shared it on twitter to see if anyone else was interested. Then I went to bed. I woke up he next morning to a lot of positive reactions than from the community (thank you). I also received many great contributions already (thank you again!).
30 |
31 | If you are interested in trying out Peacock, you can [find it here in the marketplace](https://marketplace.visualstudio.com/items?itemName=johnpapa.vscode-peacock&wt.mc_id=vscodepeacock-github-jopapa).
32 |
--------------------------------------------------------------------------------
/docs/about/license.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: License
3 | # We can even add meta tags to the page! This sets the keywords meta tag.
4 | #
5 | description: License for the Visual Studio Code Peacock extension
6 | meta:
7 | - name: keywords
8 | - content: vscode "visual studio code" peacock theme extension license
9 | ---
10 | MIT License
11 |
12 | Copyright (c) JohnPapa.net, LLC. All rights reserved.
13 |
14 | Permission is hereby granted, free of charge, to any person obtaining a copy
15 | of this software and associated documentation files (the "Software"), to deal
16 | in the Software without restriction, including without limitation the rights
17 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18 | copies of the Software, and to permit persons to whom the Software is
19 | furnished to do so, subject to the following conditions:
20 |
21 | The above copyright notice and this permission notice shall be included in all
22 | copies or substantial portions of the Software.
23 |
24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 | SOFTWARE
31 |
--------------------------------------------------------------------------------
/resources/hero.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnpapa/vscode-peacock/d2c96693dc5c27c9b0271b5ac5b4fd2eef31c5ed/resources/hero.png
--------------------------------------------------------------------------------
/resources/peacock-icon-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnpapa/vscode-peacock/d2c96693dc5c27c9b0271b5ac5b4fd2eef31c5ed/resources/peacock-icon-small.png
--------------------------------------------------------------------------------
/resources/peacock-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnpapa/vscode-peacock/d2c96693dc5c27c9b0271b5ac5b4fd2eef31c5ed/resources/peacock-icon.png
--------------------------------------------------------------------------------
/src/apply-color.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 |
3 | import { ColorSettings, extensionShortName, ISettingsIndexer } from './models';
4 | import {
5 | getColorCustomizationConfigFromWorkspace,
6 | prepareColors,
7 | updateWorkspaceConfiguration,
8 | updatePeacockColor,
9 | updatePeacockRemoteColor,
10 | } from './configuration';
11 | import { Logger } from './logging';
12 | import { updateStatusBar } from './statusbar';
13 | import {
14 | isValidColorInput,
15 | getBackgroundColorHex,
16 | deletePeacocksColorCustomizations,
17 | } from './color-library';
18 | // import { ConfigurationTarget } from 'vscode';
19 |
20 | export async function unapplyColors() {
21 | if (!vscode.workspace.workspaceFolders) {
22 | // If we are not in a workspace, don't allow Peacock to apply colors or write to settings.
23 | return;
24 | }
25 |
26 | // Overwite color customizations, without the peacock ones.
27 | // This preserves any extra ones someone might have.
28 | const colorCustomizationsWithPeacock = deletePeacocksColorCustomizations();
29 | await updateWorkspaceConfiguration(colorCustomizationsWithPeacock);
30 | updateStatusBar();
31 | }
32 |
33 | function mergeColorCustomizations(
34 | existingColors: ISettingsIndexer,
35 | updatedColors: ISettingsIndexer,
36 | ) {
37 | /**
38 | * Alays start with the existing colors.
39 | * So we clone existing into a new object that will contain
40 | * the merged (existing and updated) set of colors.
41 | */
42 | const existingColorsClone: ISettingsIndexer = { ...existingColors };
43 |
44 | /**
45 | * If any existing color settings are not in the set
46 | * that Peacock manages, remove them.
47 | */
48 | Object.values(ColorSettings)
49 | .filter(c => !(c in updatedColors))
50 | .forEach(c => delete existingColorsClone[c]);
51 |
52 | /**
53 | * Merge the updated colors on top of the existing colors.
54 | */
55 | const mergedCustomizations: ISettingsIndexer = {
56 | ...existingColorsClone,
57 | ...updatedColors,
58 | };
59 |
60 | return mergedCustomizations;
61 | }
62 |
63 | export async function applyColor(input: string) {
64 | /**************************************************************
65 | * This is the heart of Peacock logic to apply the colors.
66 | *
67 | */
68 |
69 | if (!vscode.workspace.workspaceFolders) {
70 | // If we are not in a workspace, don't allow Peacock to apply colors or write to settings.
71 | return;
72 | }
73 |
74 | if (!isValidColorInput(input)) {
75 | await unapplyColors();
76 | return;
77 | }
78 |
79 | const color = getBackgroundColorHex(input);
80 |
81 | // Get existing color customizations.
82 | const existingColors = getColorCustomizationConfigFromWorkspace();
83 |
84 | // Get updated Peacock colors.
85 | const updatedColors = prepareColors(color);
86 |
87 | const colorCustomizations = mergeColorCustomizations(existingColors, updatedColors);
88 |
89 | await updateWorkspaceConfiguration(colorCustomizations);
90 | updateStatusBar();
91 |
92 | Logger.info(`${extensionShortName}: Peacock is now using ${color}`);
93 |
94 | return color;
95 | }
96 |
97 | export async function updateColorSetting(color: string) {
98 | if (!vscode.workspace.workspaceFolders) {
99 | // If we are not in a workspace, don't allow Peacock to apply colors or write to settings.
100 | return;
101 | }
102 |
103 | if (!color) {
104 | return;
105 | }
106 |
107 | if (vscode.env.remoteName) {
108 | await updatePeacockRemoteColor(color);
109 | } else {
110 | await updatePeacockColor(color);
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/src/color-library.ts:
--------------------------------------------------------------------------------
1 | import * as tinycolor from 'tinycolor2';
2 |
3 | import {
4 | ColorAdjustment,
5 | ReadabilityRatios,
6 | inactiveElementAlpha,
7 | ColorSettings,
8 | ColorAdjustmentOptions,
9 | defaultAmountToDarkenLighten,
10 | defaultSaturation,
11 | } from './models';
12 | import {
13 | getColorCustomizationConfigFromWorkspace,
14 | getDarkForegroundColorOrOverride,
15 | getLightForegroundColorOrOverride,
16 | } from './configuration';
17 |
18 | export function getColorHex(color = '') {
19 | return formatHex(tinycolor(color));
20 | }
21 |
22 | export function getBackgroundColorHex(color = '') {
23 | return formatHex(tinycolor(color));
24 | }
25 |
26 | export function getInactiveBackgroundColorHex(backgroundColor = '') {
27 | const background = tinycolor(backgroundColor);
28 | background.setAlpha(inactiveElementAlpha);
29 | return formatHex(background);
30 | }
31 |
32 | export function getBackgroundHoverColorHex(backgroundColor = '') {
33 | const background = tinycolor(backgroundColor);
34 | const hoverColor = background.isLight() ? background.darken() : background.lighten();
35 | return formatHex(hoverColor);
36 | }
37 |
38 | export function getForegroundColorHex(backgroundColor = '') {
39 | const background = tinycolor(backgroundColor);
40 | const foreground = background.isLight()
41 | ? getDarkForegroundColorOrOverride()
42 | : getLightForegroundColorOrOverride();
43 | return formatHex(tinycolor(foreground));
44 | }
45 |
46 | export function getInactiveForegroundColorHex(backgroundColor = '') {
47 | const foreground = tinycolor(getForegroundColorHex(backgroundColor));
48 | foreground.setAlpha(inactiveElementAlpha);
49 | return formatHex(foreground);
50 | }
51 |
52 | export function getReadableAccentColorHex(backgroundColor = '', ratio = ReadabilityRatios.Text) {
53 | const background = tinycolor(backgroundColor);
54 |
55 | // Get an initial color for the badge as the first in a triad (120 degrees)
56 | // from the background color since it will be a more pleasing shade than
57 | // pure complementary (180 degrees).
58 | const foreground = background.triad()[1];
59 |
60 | // Convert the color to HSL to work with the channels individually
61 | // eslint-disable-next-line prefer-const
62 | let { h, s, l } = foreground.toHsl();
63 |
64 | // When there is no saturation we have some kind of grayscale color,
65 | // which for accent purposes should be colorized artificially
66 | if (s === 0) {
67 | // Spin the hue in the case of no saturation (grayscale). The spin is
68 | // deterministic based on the lightness of the color (0 to 1) and will
69 | // be mapped to one of the 6 primary and secondary hues (60 degree steps).
70 | h = 60 * Math.round(l * 6);
71 | }
72 |
73 | // Increase the saturation to 50% (defaultSaturation)
74 | // for any color that is very desaturated
75 | // to provide more of an accent in the manner that themes normally would
76 | if (s < 0.15) {
77 | s = defaultSaturation;
78 | }
79 |
80 | // Create an array of 16 shades of the accent color from no luminance
81 | // (black) to full luminance (white) and determine the contrast ratio
82 | // of each against the background.
83 | const shadeCount = 16;
84 | const shadeValue = 1 / shadeCount;
85 | const shadesWithRatios = [...Array(shadeCount).keys()].map(index => {
86 | const shade = tinycolor({ h, s, l: index * shadeValue });
87 | return {
88 | contrast: tinycolor.readability(shade, background),
89 | hex: formatHex(shade),
90 | };
91 | });
92 |
93 | // Sort the shades by their contrast ratio from least to greatest so that
94 | // we can find the first shade that meets the readability threshold, but has
95 | // the least contrast of those that do.
96 | shadesWithRatios.sort((shade1, shade2) => shade1.contrast - shade2.contrast);
97 | const firstReadableShade = shadesWithRatios.find(shade => {
98 | return shade.contrast >= ratio;
99 | });
100 |
101 | // Return the first readable shade that meets
102 | // the threshold or white if none of them do
103 | return firstReadableShade ? firstReadableShade.hex : '#ffffff';
104 | }
105 |
106 | export function getBadgeBackgroundColorHex(backgroundColor = '') {
107 | return getReadableAccentColorHex(backgroundColor, ReadabilityRatios.UserInterfaceLow);
108 | }
109 |
110 | export function getDebuggingBackgroundColorHex(backgroundColor = '') {
111 | return formatHex(tinycolor(backgroundColor).complement());
112 | }
113 |
114 | export function getAdjustedColorHex(color = '', adjustment: ColorAdjustment) {
115 | switch (adjustment) {
116 | case ColorAdjustmentOptions.lighten:
117 | return getLightenedColorHex(color);
118 |
119 | case ColorAdjustmentOptions.darken:
120 | return getDarkenedColorHex(color);
121 |
122 | default:
123 | return color;
124 | }
125 | }
126 | export function getLightenedColorHex(color = '', amount = defaultAmountToDarkenLighten) {
127 | return formatHex(tinycolor(color).lighten(amount));
128 | }
129 |
130 | export function getDarkenedColorHex(color: string, amount = defaultAmountToDarkenLighten) {
131 | return formatHex(tinycolor(color).darken(amount));
132 | }
133 |
134 | export function getRandomColorHex() {
135 | return formatHex(tinycolor.random());
136 | }
137 |
138 | export function getColorBrightness(input = '') {
139 | return tinycolor(input).getBrightness();
140 | }
141 |
142 | export function getColorComplementHex(input = '') {
143 | return formatHex(tinycolor(input).complement());
144 | }
145 |
146 | export function getReadabilityRatio(backgroundColor = '', foregroundColor = '') {
147 | return tinycolor.readability(tinycolor(backgroundColor), tinycolor(foregroundColor));
148 | }
149 |
150 | export function isValidColorInput(input: string) {
151 | const isValid = typeof input === 'string' && tinycolor(input).isValid();
152 | return isValid;
153 | }
154 |
155 | export function deletePeacocksColorCustomizations() {
156 | const newColorCustomizations = getColorCustomizationConfigFromWorkspace();
157 |
158 | Object.values(ColorSettings).forEach(setting => {
159 | delete newColorCustomizations[setting];
160 | });
161 | return newColorCustomizations;
162 | }
163 |
164 | function formatHex(color: tinycolor.Instance) {
165 | return color.getAlpha() < 1 ? color.toHex8String() : color.toHexString();
166 | }
167 |
--------------------------------------------------------------------------------
/src/commands.ts:
--------------------------------------------------------------------------------
1 | import {
2 | isValidColorInput,
3 | getRandomColorHex,
4 | getDarkenedColorHex,
5 | getLightenedColorHex,
6 | } from './color-library';
7 | import { applyColor, unapplyColors, updateColorSetting } from './apply-color';
8 | import { State, peacockGreen, docsUri } from './models';
9 | import {
10 | getDarkenLightenPercentage,
11 | getRandomFavoriteColor,
12 | getSurpriseMeFromFavoritesOnly,
13 | addNewFavoriteColor,
14 | writeRecommendedFavoriteColors,
15 | updatePeacockColor,
16 | getEnvironmentAwareColor,
17 | updatePeacockRemoteColor,
18 | updatePeacockRemoteColorInUserSettings,
19 | updatePeacockColorInUserSettings,
20 | } from './configuration';
21 | import { promptForColor, promptForFavoriteColor, promptForFavoriteColorName } from './inputs';
22 |
23 | import { resetLiveSharePreviousColors } from './live-share';
24 | import { notify } from './notification';
25 | import * as vscode from 'vscode';
26 |
27 | export async function removeAllPeacockColorsHandler() {
28 | await resetWorkspaceColorsHandler();
29 | await updatePeacockColorInUserSettings(undefined);
30 | await updatePeacockRemoteColorInUserSettings(undefined);
31 | return State.extensionContext;
32 | }
33 |
34 | export async function showDocumentationHandler() {
35 | await vscode.env.openExternal(docsUri);
36 | return State.extensionContext;
37 | }
38 |
39 | export async function resetWorkspaceColorsHandler() {
40 | await resetLiveSharePreviousColors();
41 | await updatePeacockColor(undefined);
42 | await updatePeacockRemoteColor(undefined);
43 | return State.extensionContext;
44 | }
45 |
46 | export async function saveColorToFavoritesHandler() {
47 | const color = getEnvironmentAwareColor();
48 | if (color) {
49 | const name = await promptForFavoriteColorName(color);
50 | if (!name) {
51 | return;
52 | }
53 | await addNewFavoriteColor(name, color);
54 | }
55 | return State.extensionContext;
56 | }
57 |
58 | export async function enterColorHandler(color?: string) {
59 | const input = color ? color : await promptForColor();
60 | if (!input) {
61 | return;
62 | }
63 | if (!isValidColorInput(input)) {
64 | throw new Error(`Invalid HEX or named color "${input}"`);
65 | }
66 | await applyColor(input);
67 | await updateColorSetting(input);
68 | return State.extensionContext;
69 | }
70 |
71 | export async function changeColorToRandomHandler() {
72 | const surpriseMeFromFavoritesOnly = getSurpriseMeFromFavoritesOnly();
73 | let color = '';
74 |
75 | if (surpriseMeFromFavoritesOnly) {
76 | const o = getRandomFavoriteColor();
77 | if (!o) {
78 | notify(
79 | 'No favorites exist. Add some favorites if you want to use the surprise me from favorites feature',
80 | );
81 | return State.extensionContext;
82 | }
83 | color = o.value;
84 | } else {
85 | color = getRandomColorHex();
86 | }
87 |
88 | await applyColor(color);
89 | await updateColorSetting(color);
90 | return State.extensionContext;
91 | }
92 |
93 | export async function addRecommendedFavoritesHandler() {
94 | await writeRecommendedFavoriteColors();
95 | return State.extensionContext;
96 | }
97 |
98 | export async function changeColorToPeacockGreenHandler() {
99 | await applyColor(peacockGreen);
100 | await updateColorSetting(peacockGreen);
101 | return State.extensionContext;
102 | }
103 |
104 | export async function changeColorToFavoriteHandler() {
105 | // Remember the color we started with
106 | const startingColor = getEnvironmentAwareColor();
107 | const favoriteColor = await promptForFavoriteColor();
108 |
109 | if (isValidColorInput(favoriteColor)) {
110 | // We have a valid Favorite color,
111 | // apply it and write the new color to settings
112 | await applyColor(favoriteColor);
113 | await updateColorSetting(favoriteColor);
114 | } else if (startingColor) {
115 | // No favorite was selected.
116 | // We need to re-apply the starting color
117 | // and write the new color to settings
118 | await applyColor(startingColor);
119 | await updateColorSetting(startingColor);
120 | } else {
121 | // No favorite was selected. We had no color to start, either.
122 | // We need re unapply the colors, and NOT write a color to settings.
123 | await unapplyColors();
124 | }
125 | return State.extensionContext;
126 | }
127 |
128 | export async function darkenHandler() {
129 | const color = getEnvironmentAwareColor();
130 | if (color) {
131 | const darkenLightenPercentage = getDarkenLightenPercentage();
132 | const darkenedColor = getDarkenedColorHex(color, darkenLightenPercentage);
133 | await applyColor(darkenedColor);
134 | await updateColorSetting(darkenedColor);
135 | }
136 | return State.extensionContext;
137 | }
138 |
139 | export async function lightenHandler() {
140 | const color = getEnvironmentAwareColor();
141 | if (color) {
142 | const darkenLightenPercentage = getDarkenLightenPercentage();
143 | const lightenedColor = getLightenedColorHex(color, darkenLightenPercentage);
144 | await applyColor(lightenedColor);
145 | await updateColorSetting(lightenedColor);
146 | }
147 | return State.extensionContext;
148 | }
149 |
150 | export async function showAndCopyCurrentColorHandler() {
151 | const color = getEnvironmentAwareColor();
152 | if (!color) {
153 | return;
154 | }
155 | const msg = color
156 | ? `Peacock's color is ${color} and has been copied to your clipboard.`
157 | : 'There is no Peacock color set at this time.';
158 | vscode.env.clipboard.writeText(color);
159 | notify(msg, true);
160 | return State.extensionContext;
161 | }
162 |
--------------------------------------------------------------------------------
/src/configuration/index.ts:
--------------------------------------------------------------------------------
1 | export * from './read-configuration';
2 | export * from './update-configuration';
3 |
--------------------------------------------------------------------------------
/src/extension.ts:
--------------------------------------------------------------------------------
1 | // The module 'vscode' contains the VS Code extensibility API
2 | // Import the module and reference it with the alias vscode in your code below
3 | import * as vscode from 'vscode';
4 | import {
5 | Commands,
6 | State,
7 | StandardSettings,
8 | extensionShortName,
9 | getExtensionVersion,
10 | ColorSource,
11 | } from './models';
12 | import {
13 | resetWorkspaceColorsHandler,
14 | enterColorHandler,
15 | changeColorToRandomHandler,
16 | changeColorToPeacockGreenHandler,
17 | changeColorToFavoriteHandler,
18 | saveColorToFavoritesHandler,
19 | addRecommendedFavoritesHandler,
20 | darkenHandler,
21 | lightenHandler,
22 | showAndCopyCurrentColorHandler,
23 | removeAllPeacockColorsHandler,
24 | showDocumentationHandler,
25 | } from './commands';
26 | import {
27 | checkIfPeacockSettingsChanged,
28 | getSurpriseMeOnStartup,
29 | writeRecommendedFavoriteColors,
30 | getEnvironmentAwareColor,
31 | inspectColor,
32 | getCurrentColorBeforeAdjustments,
33 | getFavoriteColors,
34 | } from './configuration';
35 | import { applyColor, updateColorSetting } from './apply-color';
36 | import { Logger } from './logging';
37 | import { addLiveShareIntegration } from './live-share';
38 | import { addRemoteIntegration } from './remote';
39 | import { saveFavoritesVersionGlobalMemento, getMementos } from './mementos';
40 |
41 | const { commands, workspace } = vscode;
42 |
43 | export async function activate(context: vscode.ExtensionContext) {
44 | State.extensionContext = context;
45 | // Logger.info(`${extensionShortName}: Extension "vscode-peacock" is now active!`);
46 | Logger.info(getMementos(), true, 'Peacock Mementos');
47 |
48 | registerCommands();
49 | await initializeTheStarterSetOfFavorites();
50 |
51 | if (workspace.workspaceFolders) {
52 | Logger.info('Peacock is in a workspace, so Peacock functionality is available.');
53 | /**
54 | * We only run this logic if we are in a workspace
55 | * because they may write peacock settings, and it will fail.
56 | * This entire function will re-run when a workspace is opened.
57 | */
58 | await checkSurpriseMeOnStartupLogic();
59 | await addLiveShareIntegration(State.extensionContext);
60 | await addRemoteIntegration(State.extensionContext);
61 | } else {
62 | Logger.info('Peacock is not in a workspace, so Peacock functionality is not available.');
63 | }
64 |
65 | addSubscriptions(); // add these AFTER applying initial config
66 | }
67 |
68 | function addSubscriptions() {
69 | State.extensionContext.subscriptions.push(Logger.getChannel());
70 |
71 | State.extensionContext.subscriptions.push(workspace.onDidChangeConfiguration(applyPeacock()));
72 | }
73 |
74 | function applyPeacock(): (e: vscode.ConfigurationChangeEvent) => any {
75 | return async e => {
76 | const color = getEnvironmentAwareColor();
77 | const appliedColor = getCurrentColorBeforeAdjustments();
78 | if (checkIfPeacockSettingsChanged(e) && (color || appliedColor)) {
79 | /**
80 | * If the settings have changed
81 | * AND (either we have a peacock.color/remoteColor to apply
82 | * OR we have an applied color already in the color customizations),
83 | * Then we apply the "color"
84 | */
85 | Logger.info(
86 | `${extensionShortName}: Configuration changed. Changing the color to most recently selected color: ${color}`,
87 | );
88 | await applyColor(color);
89 |
90 | // Only update the color in the workspace settings
91 | // if there was already a workspace setting
92 | const colorSource = inspectColor();
93 | if (colorSource.colorSource === ColorSource.WorkspaceValue) {
94 | await updateColorSetting(color);
95 | }
96 | }
97 | };
98 | }
99 |
100 | function registerCommands() {
101 | commands.registerCommand(Commands.showDocumentation, showDocumentationHandler);
102 | commands.registerCommand(Commands.resetWorkspaceColors, resetWorkspaceColorsHandler);
103 | commands.registerCommand(Commands.removeAllColors, removeAllPeacockColorsHandler);
104 | commands.registerCommand(Commands.saveColorToFavorites, saveColorToFavoritesHandler);
105 | commands.registerCommand(Commands.enterColor, enterColorHandler);
106 | commands.registerCommand(Commands.changeColorToRandom, changeColorToRandomHandler);
107 | commands.registerCommand(Commands.addRecommendedFavorites, addRecommendedFavoritesHandler);
108 | commands.registerCommand(Commands.changeColorToPeacockGreen, changeColorToPeacockGreenHandler);
109 | commands.registerCommand(Commands.changeColorToFavorite, changeColorToFavoriteHandler);
110 | commands.registerCommand(Commands.darken, darkenHandler);
111 | commands.registerCommand(Commands.lighten, lightenHandler);
112 | commands.registerCommand(Commands.showAndCopyCurrentColor, showAndCopyCurrentColorHandler);
113 | }
114 |
115 | export function deactivate() {
116 | // Logger.info(`${extensionShortName}: Extension "vscode-peacock" is now deactive`);
117 | }
118 |
119 | async function initializeTheStarterSetOfFavorites() {
120 | // If the version has changed, we write the current set of favorites to user settings.json,
121 | // merging them with any the user has created on their own
122 | const currentVersion = getExtensionVersion();
123 | // TODO: Revisit how we merge favorites
124 | // For now we'll just add the starter set of favorites one time.
125 | // If there are favorites, do not write new ones.
126 | // We'll revisit this later so we do not overwrite favorites.
127 | const { values: favoritesValues } = getFavoriteColors();
128 | if (!favoritesValues.length) {
129 | await writeRecommendedFavoriteColors();
130 | await saveFavoritesVersionGlobalMemento(currentVersion);
131 | }
132 | }
133 |
134 | export async function checkSurpriseMeOnStartupLogic() {
135 | /**
136 | * If the "surprise me on startup" setting is true
137 | * and there is no peacock color set, then choose a new random color.
138 | * We do not choose a random color if there is already a color set
139 | * as this would confuse users who choose a specific color in a
140 | * workspace and see it changed to the "surprise" color
141 | */
142 | const peacockColor = getEnvironmentAwareColor();
143 | if (getSurpriseMeOnStartup()) {
144 | if (peacockColor) {
145 | const message = `Peacock did not change the color using "surprise me on startup" because the color ${peacockColor} was already set.`;
146 | Logger.info(message);
147 | return;
148 | }
149 |
150 | await changeColorToRandomHandler();
151 | const color = getEnvironmentAwareColor();
152 | const message = `Peacock changed the color to ${color}, because the setting is enabled for ${StandardSettings.SurpriseMeOnStartup}`;
153 | Logger.info(message);
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/src/inputs.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import { favoriteColorSeparator, peacockGreen } from './models';
3 | import { getFavoriteColors } from './configuration';
4 | import { applyColor } from './apply-color';
5 |
6 | export async function promptForColor() {
7 | const options: vscode.InputBoxOptions = {
8 | ignoreFocusOut: true,
9 | placeHolder: peacockGreen,
10 | prompt:
11 | 'Enter a background color for the title bar in RGB hex format or a valid HTML color name',
12 | value: peacockGreen,
13 | };
14 | const inputColor = (await vscode.window.showInputBox(options)) || '';
15 | return inputColor.trim();
16 | }
17 |
18 | export async function promptForFavoriteColorName(color: string) {
19 | if (!color) {
20 | return;
21 | }
22 | const options: vscode.InputBoxOptions = {
23 | ignoreFocusOut: true,
24 | placeHolder: 'Mandalorian Blue',
25 | prompt: `Enter a name for the color ${color}`,
26 | value: '',
27 | };
28 | const inputName = await vscode.window.showInputBox(options);
29 | return inputName || '';
30 | }
31 |
32 | export async function promptForFavoriteColor() {
33 | const { menu, values: favoriteColors } = getFavoriteColors();
34 | let selection = '';
35 | const options = {
36 | placeHolder: 'Pick a favorite color',
37 | onDidSelectItem: await tryColorWithPeacock(),
38 | };
39 | if (favoriteColors && favoriteColors.length) {
40 | selection = (await vscode.window.showQuickPick(menu, options)) || '';
41 | }
42 | if (selection) {
43 | const selectedColor = parseFavoriteColorValue(selection);
44 | return selectedColor || '';
45 | }
46 |
47 | return '';
48 | }
49 |
50 | export function parseFavoriteColorValue(text: string) {
51 | const sep = favoriteColorSeparator;
52 | return text.substring(text.indexOf(sep) + sep.length + 1);
53 | }
54 |
55 | async function tryColorWithPeacock() {
56 | return async (item: string) => {
57 | const color = parseFavoriteColorValue(item);
58 | return await applyColor(color);
59 | };
60 | }
61 |
--------------------------------------------------------------------------------
/src/live-share/enums.ts:
--------------------------------------------------------------------------------
1 | /* istanbul ignore file */
2 | export enum LiveShareCommands {
3 | changeColorOfLiveShareHost = 'peacock.changeColorOfLiveShareHost',
4 | changeColorOfLiveShareGuest = 'peacock.changeColorOfLiveShareGuest',
5 | }
6 |
7 | export enum LiveShareSettings {
8 | VSLSShareColor = 'vslsShareColor',
9 | VSLSJoinColor = 'vslsJoinColor',
10 | }
11 |
--------------------------------------------------------------------------------
/src/live-share/index.ts:
--------------------------------------------------------------------------------
1 | /* istanbul ignore file */
2 | export * from './enums';
3 | export * from './integration';
4 | export * from './liveshare-commands';
5 |
--------------------------------------------------------------------------------
/src/live-share/integration.ts:
--------------------------------------------------------------------------------
1 | /* istanbul ignore file */
2 | import * as vsls from 'vsls';
3 | import * as vscode from 'vscode';
4 |
5 | import { applyColor } from '../apply-color';
6 | import { registerLiveShareIntegrationCommands } from './liveshare-commands';
7 | import { State } from '../models';
8 | import { notify } from '../notification';
9 | import { LiveShareSettings } from './enums';
10 | import {
11 | getLiveShareColor,
12 | getColorCustomizationConfigFromWorkspace,
13 | updateWorkspaceConfiguration,
14 | } from '../configuration';
15 |
16 | let peacockColorCustomizations: any;
17 |
18 | export async function revertLiveShareWorkspaceColors() {
19 | await updateWorkspaceConfiguration(peacockColorCustomizations);
20 |
21 | peacockColorCustomizations = null;
22 | }
23 |
24 | async function setLiveShareSessionWorkspaceColors(isHost: boolean) {
25 | const colorSettingName = isHost
26 | ? LiveShareSettings.VSLSShareColor
27 | : LiveShareSettings.VSLSJoinColor;
28 |
29 | const liveShareColorSetting = getLiveShareColor(colorSettingName);
30 | if (!liveShareColorSetting) {
31 | return;
32 | }
33 |
34 | await applyColor(liveShareColorSetting);
35 | }
36 |
37 | export async function refreshLiveShareSessionColor(isHostRole: boolean): Promise {
38 | const vslsApi = await vsls.getApi();
39 |
40 | // not in Live Share session, no need to update
41 | if (!vslsApi || !vslsApi.session.id) {
42 | const verb = isHostRole ? 'host and share' : 'join';
43 |
44 | notify(`The selected color will be applied every time you ${verb} a Live Share session.`, true);
45 |
46 | return false;
47 | }
48 |
49 | const isHost = vslsApi.session.role === vsls.Role.Host;
50 | await setLiveShareSessionWorkspaceColors(isHost);
51 | return true;
52 | }
53 |
54 | export async function addLiveShareIntegration(context: vscode.ExtensionContext) {
55 | State.extensionContext = context;
56 |
57 | registerLiveShareIntegrationCommands();
58 |
59 | const vslsApi = await vsls.getApi();
60 | await vscode.commands.executeCommand('setContext', 'peacock:liveshare', !!vslsApi);
61 |
62 | if (!vslsApi) {
63 | return;
64 | }
65 |
66 | vslsApi!.onDidChangeSession(async e => {
67 | // If there isn't a session ID, then that
68 | // means the session has been ended.
69 | if (!e.session.id) {
70 | return await revertLiveShareWorkspaceColors();
71 | }
72 |
73 | // we need to update `peacockColorCustomizations` only when it is `undefined`
74 | // to prevent the case of multiple color changes during live share session
75 | peacockColorCustomizations = await getColorCustomizationConfigFromWorkspace();
76 |
77 | const isHost = e.session.role === vsls.Role.Host;
78 | return await setLiveShareSessionWorkspaceColors(isHost);
79 | });
80 | }
81 |
--------------------------------------------------------------------------------
/src/live-share/liveshare-commands.ts:
--------------------------------------------------------------------------------
1 | /* istanbul ignore file */
2 | import { commands } from 'vscode';
3 |
4 | import { promptForFavoriteColor } from '../inputs';
5 | import { isValidColorInput } from '../color-library';
6 | import { applyColor } from '../apply-color';
7 | import { LiveShareCommands, LiveShareSettings } from './enums';
8 | import { refreshLiveShareSessionColor, revertLiveShareWorkspaceColors } from './integration';
9 | import { updateLiveShareColor, getEnvironmentAwareColor } from '../configuration';
10 | import { State } from '../models';
11 |
12 | const changeColorOfLiveShareSessionFactory = (isHost: boolean) => {
13 | return async function changeColorOfLiveShareSession() {
14 | const startingColor = getEnvironmentAwareColor();
15 | const input = await promptForFavoriteColor();
16 |
17 | if (isValidColorInput(input)) {
18 | const settingName = isHost
19 | ? LiveShareSettings.VSLSShareColor
20 | : LiveShareSettings.VSLSJoinColor;
21 |
22 | await updateLiveShareColor(settingName, input);
23 | }
24 |
25 | const isRefreshed = await refreshLiveShareSessionColor(isHost);
26 | // we are in the session and have updated the color, so return
27 | if (isRefreshed) {
28 | return State.extensionContext;
29 | }
30 | // if there is was no color prior to the color picker,
31 | // revert all the color settings
32 | if (!startingColor) {
33 | await revertLiveShareWorkspaceColors();
34 | return State.extensionContext;
35 | // if there was a color set prior to color picker,
36 | // set that color back
37 | } else {
38 | await applyColor(startingColor);
39 | }
40 |
41 | return State.extensionContext;
42 | };
43 | };
44 |
45 | export const changeColorOfLiveShareHostHandler = changeColorOfLiveShareSessionFactory(true);
46 | export const changeColorOfLiveShareGuestHandler = changeColorOfLiveShareSessionFactory(false);
47 |
48 | export function registerLiveShareIntegrationCommands() {
49 | commands.registerCommand(
50 | LiveShareCommands.changeColorOfLiveShareHost,
51 | changeColorOfLiveShareHostHandler,
52 | );
53 | commands.registerCommand(
54 | LiveShareCommands.changeColorOfLiveShareGuest,
55 | changeColorOfLiveShareGuestHandler,
56 | );
57 | }
58 |
59 | export async function resetLiveSharePreviousColors() {
60 | await updateLiveShareColor(LiveShareSettings.VSLSShareColor, undefined);
61 | await updateLiveShareColor(LiveShareSettings.VSLSJoinColor, undefined);
62 | }
63 |
--------------------------------------------------------------------------------
/src/live-share/test/runTest.ts:
--------------------------------------------------------------------------------
1 | import * as path from 'path';
2 |
3 | import { runTests } from 'vscode-test';
4 |
5 | async function main() {
6 | try {
7 | // The folder containing the Extension Manifest package.json
8 | // Passed to `--extensionDevelopmentPath`
9 | const extensionDevelopmentPath = path.resolve(__dirname, '../../../');
10 |
11 | // The path to test runner
12 | // Passed to --extensionTestsPath
13 | const extensionTestsPath = path.resolve(__dirname, './suite/index');
14 |
15 | // Download VS Code, unzip it and run the integration test
16 | await runTests({
17 | extensionDevelopmentPath,
18 | extensionTestsPath,
19 | launchArgs: [
20 | './testworkspace',
21 | // '--disable-extensions'
22 | // '${workspaceFolder}/testworkspace'
23 | ],
24 | });
25 | } catch (err) {
26 | console.error('Failed to run tests');
27 | process.exit(1);
28 | }
29 | }
30 |
31 | main();
32 |
--------------------------------------------------------------------------------
/src/live-share/test/suite/index.ts:
--------------------------------------------------------------------------------
1 | import * as path from 'path';
2 | import * as Mocha from 'mocha';
3 | import * as glob from 'glob';
4 |
5 | export function run(): Promise {
6 | // Create the mocha test
7 | const mocha = new Mocha({
8 | ui: 'tdd',
9 | //----------------------------------------
10 | // Stuff from old test setup
11 | timeout: 200000, // longer timeout, in case
12 | // useColors: true, // colored output from test results
13 | //----------------------------------------
14 | });
15 | // mocha.useColors(true);
16 |
17 | const testsRoot = path.resolve(__dirname, '..');
18 |
19 | return new Promise((c, e) => {
20 | glob('**/**.test.js', { cwd: testsRoot }, (err, files) => {
21 | if (err) {
22 | return e(err);
23 | }
24 |
25 | // Add files to the test suite
26 | files.forEach(f => mocha.addFile(path.resolve(testsRoot, f)));
27 |
28 | try {
29 | // Run the mocha test
30 | mocha.run((failures: any) => {
31 | if (failures > 0) {
32 | e(new Error(`${failures} tests failed.`));
33 | } else {
34 | c();
35 | }
36 | });
37 | } catch (err) {
38 | e(err);
39 | }
40 | });
41 | });
42 | }
43 |
--------------------------------------------------------------------------------
/src/logging.ts:
--------------------------------------------------------------------------------
1 | import { OutputChannel, window } from 'vscode';
2 |
3 | export class Logger {
4 | private static _outputChannel: OutputChannel;
5 |
6 | static initialize() {
7 | if (!this._outputChannel) {
8 | // Only init once
9 | this._outputChannel = window.createOutputChannel('Peacock');
10 | }
11 | }
12 |
13 | static getChannel() {
14 | this.initialize();
15 | return this._outputChannel;
16 | }
17 |
18 | static info(value: string | object | undefined, indent = false, title = '') {
19 | if (title) {
20 | this._outputChannel.appendLine(title);
21 | }
22 | const message = prepareMessage(value, indent);
23 | this._outputChannel.appendLine(message);
24 | }
25 | }
26 |
27 | function prepareMessage(value: string | object | undefined, indent: boolean) {
28 | const prefix = indent ? ' ' : '';
29 | let text = '';
30 | if (typeof value === 'object') {
31 | if (Array.isArray(value)) {
32 | text = `${prefix}${JSON.stringify(value, null, 2)}`;
33 | } else {
34 | Object.entries(value).map(item => {
35 | text += `${prefix}${item[0]} = ${item[1]}\n`;
36 | });
37 | }
38 | return text;
39 | }
40 | text = `${prefix}${value}`;
41 | return text;
42 | }
43 |
44 | Logger.initialize();
45 |
--------------------------------------------------------------------------------
/src/mementos.ts:
--------------------------------------------------------------------------------
1 | import { peacockMementos, extensionShortName, State } from './models';
2 | import { Logger } from './logging';
3 |
4 | export interface IMementoLog {
5 | name: string;
6 | type: 'workspaceState' | 'globalState';
7 | value: any;
8 | }
9 |
10 | async function saveGlobalMemento(mementoName: string, value: any) {
11 | if (mementoName) {
12 | Logger.info(
13 | `${extensionShortName}: Saving the globalState ${mementoName} memento with value ${value}`,
14 | );
15 | await State.extensionContext.globalState.update(mementoName, value);
16 | }
17 | }
18 |
19 | export async function saveFavoritesVersionGlobalMemento(version: string) {
20 | saveGlobalMemento(peacockMementos.favoritesVersion, version);
21 | }
22 |
23 | export function getFavoritesVersionGlobalMemento() {
24 | return State.extensionContext.globalState.get(peacockMementos.favoritesVersion, '');
25 | }
26 |
27 | export async function resetFavoritesVersionMemento() {
28 | const ec = State.extensionContext;
29 |
30 | Logger.info(
31 | `${extensionShortName}: Setting all workspaceState and globalState mementos to undefined`,
32 | );
33 |
34 | // Global
35 | await ec.globalState.update(peacockMementos.favoritesVersion, undefined);
36 | }
37 |
38 | export function getMementos() {
39 | const ec = State.extensionContext;
40 | const mementos: IMementoLog[] = [];
41 |
42 | // Globals
43 | mementos.push({
44 | name: peacockMementos.favoritesVersion,
45 | type: 'globalState',
46 | value: ec.globalState.get(peacockMementos.favoritesVersion),
47 | });
48 |
49 | return mementos;
50 | }
51 |
--------------------------------------------------------------------------------
/src/models/constants.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 |
3 | export const extensionShortName = 'peacock';
4 | export const extensionId = 'johnpapa.vscode-peacock';
5 | export const favoriteColorSeparator = '->';
6 |
7 | export const docsUri = vscode.Uri.parse('https://www.peacockcode.dev');
8 |
9 | // Matches the default inactive alpha in VS Code of 0x99
10 | // represented in 0-1 range for tinycolor.setAlpha()
11 | export const inactiveElementAlpha = 0x99 / 0xff;
12 |
13 | export const defaultAmountToDarkenLighten = 10;
14 |
15 | export const defaultSaturation = 0.5;
16 |
17 | export const azureBlue = '#007fff';
18 | export const peacockGreen = '#42b883';
19 |
20 | export const peacockMementos = {
21 | favoritesVersion: `${extensionShortName}.favoritesVersion`,
22 | };
23 |
24 | export const timeout = async (ms = 200) => new Promise(resolve => setTimeout(resolve, ms));
25 |
26 | export const isObjectEmpty = (o: {} | undefined) =>
27 | typeof o === 'object' && Object.keys(o).length === 0;
28 |
--------------------------------------------------------------------------------
/src/models/enums.ts:
--------------------------------------------------------------------------------
1 | import { LiveShareSettings } from '../live-share';
2 |
3 | export enum StandardSettings {
4 | Color = 'color',
5 | DarkenLightenPercentage = 'darkenLightenPercentage',
6 | DarkForegroundColor = 'darkForegroundColor',
7 | ElementAdjustments = 'elementAdjustments',
8 | FavoriteColors = 'favoriteColors',
9 | KeepBadgeColor = 'keepBadgeColor',
10 | KeepForegroundColor = 'keepForegroundColor',
11 | LightForegroundColor = 'lightForegroundColor',
12 | RemoteColor = 'remoteColor',
13 | ShowColorInStatusBar = 'showColorInStatusBar',
14 | SquigglyBeGone = 'squigglyBeGone',
15 | SurpriseMeFromFavoritesOnly = 'surpriseMeFromFavoritesOnly',
16 | SurpriseMeOnStartup = 'surpriseMeOnStartup',
17 | }
18 |
19 | export enum AffectedSettings {
20 | EditorGroupBorder = 'affectEditorGroupBorder',
21 | PanelBorder = 'affectPanelBorder',
22 | SideBarBorder = 'affectSideBarBorder',
23 | SashHover = 'affectSashHover',
24 | ActivityBar = 'affectActivityBar',
25 | DebuggingStatusBar = 'affectDebuggingStatusBar',
26 | StatusBar = 'affectStatusBar',
27 | StatusAndTitleBorders = 'affectStatusAndTitleBorders',
28 | TabActiveBorder = 'affectTabActiveBorder',
29 | TitleBar = 'affectTitleBar',
30 | }
31 |
32 | export type AllSettings = StandardSettings | AffectedSettings | LiveShareSettings;
33 |
34 | export enum Commands {
35 | addRecommendedFavorites = 'peacock.addRecommendedFavorites',
36 | changeColorToRandom = 'peacock.changeColorToRandom',
37 | changeColorToPeacockGreen = 'peacock.changeColorToPeacockGreen',
38 | changeColorToFavorite = 'peacock.changeColorToFavorite',
39 | darken = 'peacock.darken',
40 | enterColor = 'peacock.enterColor',
41 | lighten = 'peacock.lighten',
42 | removeAllColors = 'peacock.removeAllColors',
43 | resetWorkspaceColors = 'peacock.resetWorkspaceColors',
44 | saveColorToFavorites = 'peacock.saveColorToFavorites',
45 | showAndCopyCurrentColor = 'peacock.showAndCopyCurrentColor',
46 | showDocumentation = 'peacock.docs',
47 | }
48 |
49 | export enum ElementNames {
50 | activityBar = 'activityBar',
51 | statusBar = 'statusBar',
52 | titleBar = 'titleBar',
53 | }
54 |
55 | export enum ColorSettings {
56 | activityBar_activeBackground = 'activityBar.activeBackground',
57 | activityBar_background = 'activityBar.background',
58 | activityBar_foreground = 'activityBar.foreground',
59 | activityBar_inactiveForeground = 'activityBar.inactiveForeground',
60 | activityBar_badgeBackground = 'activityBarBadge.background',
61 | activityBar_badgeForeground = 'activityBarBadge.foreground',
62 | commandCenter_border = 'commandCenter.border',
63 | editorGroupBorder = 'editorGroup.border',
64 | panelBorder = 'panel.border',
65 | sideBarBorder = 'sideBar.border',
66 | sashHover = 'sash.hoverBorder',
67 | squigglyBeGone_error = 'editorError.foreground',
68 | squigglyBeGone_warning = 'editorWarning.foreground',
69 | squigglyBeGone_info = 'editorInfo.foreground',
70 | statusBar_border = 'statusBar.border',
71 | statusBar_background = 'statusBar.background',
72 | statusBar_foreground = 'statusBar.foreground',
73 | statusBar_debuggingBorder = 'statusBar.debuggingBorder',
74 | statusBar_debuggingBackground = 'statusBar.debuggingBackground',
75 | statusBar_debuggingForeground = 'statusBar.debuggingForeground',
76 | statusBarItem_hoverBackground = 'statusBarItem.hoverBackground',
77 | statusBarItem_remoteBackground = 'statusBarItem.remoteBackground',
78 | statusBarItem_remoteForeground = 'statusBarItem.remoteForeground',
79 | tabActiveBorder = 'tab.activeBorder',
80 | titleBar_activeBackground = 'titleBar.activeBackground',
81 | titleBar_activeForeground = 'titleBar.activeForeground',
82 | titleBar_border = 'titleBar.border',
83 | titleBar_inactiveBackground = 'titleBar.inactiveBackground',
84 | titleBar_inactiveForeground = 'titleBar.inactiveForeground',
85 | }
86 |
87 | export type ColorAdjustment = 'lighten' | 'darken' | 'none';
88 |
89 | export enum ColorAdjustmentOptions {
90 | lighten = 'lighten',
91 | darken = 'darken',
92 | none = 'none',
93 | }
94 |
95 | export enum Sections {
96 | peacockColorCustomizationSection = 'workbench.colorCustomizations',
97 | peacockSection = 'peacock',
98 | }
99 |
100 | export enum ForegroundColors {
101 | DarkForeground = '#15202b',
102 | LightForeground = '#e7e7e7',
103 | }
104 |
105 | // See WebAIM contrast guidelines: https://webaim.org/articles/contrast/
106 | export enum ReadabilityRatios {
107 | UserInterfaceLow = 2,
108 | UserInterface = 3,
109 | Text = 4.5,
110 | }
111 |
112 | export enum ColorSource {
113 | WorkspaceValue = 'workspaceValue',
114 | GlobalValue = 'globalValue',
115 | DefaultValue = 'defaultValue',
116 | None = 'none',
117 | }
118 |
--------------------------------------------------------------------------------
/src/models/favorites.ts:
--------------------------------------------------------------------------------
1 | export const starterSetOfFavorites = [
2 | { name: 'Angular Red', value: '#dd0531' },
3 | { name: 'Azure Blue', value: '#007fff' },
4 | { name: 'JavaScript Yellow', value: '#f9e64f' },
5 | { name: 'Mandalorian Blue', value: '#1857a4' },
6 | { name: 'Node Green', value: '#215732' },
7 | { name: 'React Blue', value: '#61dafb' },
8 | { name: 'Something Different', value: '#832561' },
9 | { name: 'Svelte Orange', value: '#ff3d00' },
10 | { name: 'Vue Green', value: '#42b883' },
11 | ];
12 |
--------------------------------------------------------------------------------
/src/models/index.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import { extensionId } from './constants';
3 |
4 | export * from './constants';
5 | export * from './enums';
6 | export * from './favorites';
7 | export * from './interfaces';
8 | export * from './state';
9 |
10 | export function getExtension() {
11 | let extension: vscode.Extension | undefined;
12 | const ext = vscode.extensions.getExtension(extensionId);
13 | if (!ext) {
14 | throw new Error('Extension was not found.');
15 | }
16 | if (ext) {
17 | extension = ext;
18 | }
19 | return extension;
20 | }
21 |
--------------------------------------------------------------------------------
/src/models/interfaces.ts:
--------------------------------------------------------------------------------
1 | import { ColorAdjustment, ElementNames } from './enums';
2 |
3 | export interface ISettingsIndexer {
4 | [key: string]: any;
5 | }
6 |
7 | export interface IFavoriteColors {
8 | name: string;
9 | value: string;
10 | }
11 |
12 | export interface ICommand {
13 | title: string;
14 | command: string;
15 | category: string;
16 | }
17 |
18 | export interface IConfiguration {
19 | type: string;
20 | title: string;
21 | properties: any;
22 | }
23 |
24 | export interface IElementStyle {
25 | backgroundHex: string;
26 | backgroundHoverHex: string;
27 | foregroundHex: string;
28 | inactiveBackgroundHex: string;
29 | inactiveForegroundHex: string;
30 | badgeBackgroundHex?: string;
31 | badgeForegroundHex?: string;
32 | }
33 |
34 | export interface IPeacockAffectedElementSettings {
35 | activityBar: boolean;
36 | statusBar: boolean;
37 | debuggingStatusBar: boolean;
38 | titleBar: boolean;
39 | editorGroupBorder: boolean;
40 | panelBorder: boolean;
41 | sideBarBorder: boolean;
42 | sashHover: boolean;
43 | statusAndTitleBorders: boolean;
44 | tabActiveBorder: boolean;
45 | }
46 |
47 | export interface IPeacockElementAdjustments {
48 | [elementName: string]: ColorAdjustment;
49 | }
50 |
51 | export interface IPeacockSettings {
52 | affectedElements: IPeacockAffectedElementSettings;
53 | editorGroupBorder: boolean;
54 | panelBorder: boolean;
55 | sideBarBorder: boolean;
56 | sashHover: boolean;
57 | affectStatusAndTitleBorders: boolean;
58 | elementAdjustments: IPeacockElementAdjustments;
59 | favoriteColors: IFavoriteColors[];
60 | keepBadgeColor: boolean;
61 | keepForegroundColor: boolean;
62 | darkForegroundColor: string;
63 | lightForegroundColor: string;
64 | darkenLightenPercentage: number;
65 | showColorInStatusBar: boolean;
66 | squigglyBeGone: boolean;
67 | surpriseMeFromFavoritesOnly: boolean;
68 | surpriseMeOnStartup: boolean;
69 | color: string;
70 | remoteColor: string;
71 | }
72 |
73 | export interface IElementColors {
74 | [ElementNames.activityBar]: string;
75 | [ElementNames.statusBar]: string;
76 | [ElementNames.titleBar]: string;
77 | }
78 |
--------------------------------------------------------------------------------
/src/models/state.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import { getExtension } from './';
3 |
4 | export class State {
5 | private static _extContext: vscode.ExtensionContext;
6 |
7 | public static get extensionContext(): vscode.ExtensionContext {
8 | return this._extContext;
9 | }
10 |
11 | public static set extensionContext(ec: vscode.ExtensionContext) {
12 | this._extContext = ec;
13 | }
14 | }
15 |
16 | export function getExtensionVersion() {
17 | const extension = getExtension();
18 | const version: string = extension ? extension.packageJSON.version : '';
19 | return version;
20 | }
21 |
--------------------------------------------------------------------------------
/src/notification.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import { Logger } from './logging';
3 |
4 | export const notify = (message: string, log = false) => {
5 | vscode.window.showInformationMessage(message);
6 | if (log) {
7 | Logger.info(message);
8 | }
9 | };
10 |
--------------------------------------------------------------------------------
/src/object-library.ts:
--------------------------------------------------------------------------------
1 | import { ISettingsIndexer } from './models';
2 |
3 | export function sortSettingsIndexer(unordered: ISettingsIndexer) {
4 | const ordered: ISettingsIndexer = {};
5 | Object.keys(unordered)
6 | .sort()
7 | .forEach(key => (ordered[key] = unordered[key]));
8 | return ordered;
9 | }
10 |
--------------------------------------------------------------------------------
/src/remote/enums.ts:
--------------------------------------------------------------------------------
1 | export enum RemoteNames {
2 | wsl = 'wsl',
3 | sshRemote = 'ssh-remote',
4 | devContainer = 'dev-container',
5 | }
6 |
--------------------------------------------------------------------------------
/src/remote/index.ts:
--------------------------------------------------------------------------------
1 | export * from './enums';
2 | export * from './integration';
3 |
--------------------------------------------------------------------------------
/src/remote/integration.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 |
3 | import { applyColor } from '../apply-color';
4 | import { State } from '../models';
5 | import { getPeacockRemoteColor, getPeacockColor } from '../configuration';
6 |
7 | // function remoteExtensionsInstalled(): boolean {
8 | // let remoteExtensions = [
9 | // 'ms-vscode-remote.remote-containers',
10 | // 'ms-vscode-remote.remote-ssh',
11 | // 'ms-vscode-remote.remote-wsl',
12 | // ];
13 | // return !!remoteExtensions.find(each => !!vscode.extensions.getExtension(each));
14 | // }
15 |
16 | export async function addRemoteIntegration(context: vscode.ExtensionContext) {
17 | State.extensionContext = context;
18 |
19 | // const remoteExtensions = remoteExtensionsInstalled();
20 | // await vscode.commands.executeCommand('setContext', 'peacock:remote', remoteExtensions);
21 |
22 | if (vscode.env.remoteName) {
23 | const remoteColor = getPeacockRemoteColor();
24 | await applyColor(remoteColor);
25 | } else {
26 | const peacockColor = getPeacockColor();
27 | await applyColor(peacockColor);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/statusbar.ts:
--------------------------------------------------------------------------------
1 | import { StatusBarAlignment, window, StatusBarItem } from 'vscode';
2 | import { getShowColorInStatusBar, getEnvironmentAwareColor } from './configuration';
3 | import { Commands } from './models';
4 |
5 | const _statusBarItem: StatusBarItem = window.createStatusBarItem(StatusBarAlignment.Left);
6 |
7 | export const getStatusBarItem = () => {
8 | updateStatusBar();
9 | return _statusBarItem;
10 | };
11 |
12 | export function clearStatusBar() {
13 | const sb = _statusBarItem;
14 | sb.text = '';
15 | sb.hide();
16 | }
17 |
18 | export function updateStatusBar() {
19 | const sb = _statusBarItem;
20 | const show = getShowColorInStatusBar();
21 | const color = getEnvironmentAwareColor();
22 | sb.text = `$(paintcan) ${color}`;
23 | sb.command = Commands.showAndCopyCurrentColor;
24 | sb.tooltip = 'Copy the Peacock color';
25 | if (show && !!color) {
26 | sb.show();
27 | } else {
28 | clearStatusBar();
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/test/coverage.ts:
--------------------------------------------------------------------------------
1 | import * as iLibInstrument from 'istanbul-lib-instrument';
2 | import * as iLibCoverage from 'istanbul-lib-coverage';
3 | import * as iLibSourceMaps from 'istanbul-lib-source-maps';
4 | import * as iLibReport from 'istanbul-lib-report';
5 | import * as iReports from 'istanbul-reports';
6 |
7 | import * as fs from 'fs';
8 | import * as path from 'path';
9 |
10 | const REPO_ROOT = path.resolve(__dirname, '../..');
11 |
12 | export function instrument() {
13 | const instrumenter = iLibInstrument.createInstrumenter();
14 | const files = rreaddir(path.resolve(REPO_ROOT, 'out'));
15 |
16 | for (let i = 0; i < files.length; i++) {
17 | const file = files[i];
18 |
19 | if (/\.js\.map$/.test(file)) {
20 | // console.log(`ignoring ${file}`);
21 | continue;
22 | }
23 |
24 | const inputPath = path.resolve(REPO_ROOT, 'out', files[i]);
25 | const outputPath = path.resolve(REPO_ROOT, 'out-cov', files[i]);
26 |
27 | if (!/\.js$/.test(file) || /(^|[\\/])test[\\/]/.test(file)) {
28 | // console.log(`copying ${inputPath}`);
29 | copyFile(inputPath, outputPath);
30 | continue;
31 | }
32 |
33 | // Try to find a .map file
34 | let map = null;
35 | try {
36 | map = JSON.parse(fs.readFileSync(`${inputPath}.map`).toString());
37 | } catch (err) {
38 | // missing source map...
39 | }
40 |
41 | // console.log(`instrumenting ${inputPath}...`);
42 | const instrumentedCode = instrumenter.instrumentSync(
43 | fs.readFileSync(inputPath).toString(),
44 | inputPath,
45 | map,
46 | );
47 | safeWriteFile(outputPath, instrumentedCode);
48 | }
49 | }
50 |
51 | export function createReport(): void {
52 | const global = new Function('return this')();
53 |
54 | const mapStore = iLibSourceMaps.createSourceMapStore();
55 | const coverageMap = iLibCoverage.createCoverageMap(global.__coverage__);
56 | const transformed = mapStore.transformCoverage(coverageMap);
57 |
58 | const watermarks = {
59 | statements: [50, 80],
60 | functions: [50, 80],
61 | branches: [50, 80],
62 | lines: [50, 80],
63 | };
64 |
65 | const tree = iLibReport.summarizers.flat(transformed.map);
66 | const context = iLibReport.createContext({
67 | dir: path.resolve(REPO_ROOT, `coverage`),
68 | watermarks,
69 | });
70 |
71 | const reports = [
72 | iReports.create('json'),
73 | iReports.create('lcov'),
74 | iReports.create('html'),
75 | iReports.create('cobertura'),
76 | ];
77 | reports.forEach(report => tree.visit(report, context));
78 | }
79 |
80 | function copyFile(inputPath: string, outputPath: string): void {
81 | safeWriteFile(outputPath, fs.readFileSync(inputPath));
82 | }
83 |
84 | function safeWriteFile(filePath: string, contents: Buffer | string): void {
85 | ensureDir(path.dirname(filePath));
86 | fs.writeFileSync(filePath, contents);
87 | }
88 |
89 | function ensureDir(dirname: string): void {
90 | if (fs.existsSync(dirname)) {
91 | return;
92 | }
93 | ensureDir(path.dirname(dirname));
94 | fs.mkdirSync(dirname);
95 | }
96 |
97 | function rreaddir(dirname: string): string[] {
98 | const result: string[] = [];
99 | _rreaddir(dirname, dirname, result);
100 | return result;
101 | }
102 |
103 | function _rreaddir(dirname: string, relativeTo: string, result: string[]): void {
104 | const entries = fs.readdirSync(dirname);
105 | for (let i = 0; i < entries.length; i++) {
106 | const entry = entries[i];
107 | const entryPath = path.join(dirname, entry);
108 | if (fs.statSync(entryPath).isDirectory()) {
109 | _rreaddir(entryPath, relativeTo, result);
110 | } else {
111 | result.push(path.relative(relativeTo, entryPath));
112 | }
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/src/test/runTest.ts:
--------------------------------------------------------------------------------
1 | import * as path from 'path';
2 |
3 | import { runTests } from 'vscode-test';
4 |
5 | import { instrument } from './coverage';
6 |
7 | async function main() {
8 | try {
9 | // The folder containing the Extension Manifest package.json
10 | // Passed to `--extensionDevelopmentPath`
11 | const extensionDevelopmentPath = path.resolve(__dirname, '../../');
12 |
13 | // The path to test runner
14 | // Passed to --extensionTestsPath
15 | let extensionTestsPath = path.resolve(__dirname, './suite/index');
16 |
17 | if (process.argv.indexOf('--coverage') >= 0) {
18 | // generate instrumented files at out-cov
19 | instrument();
20 |
21 | // load the instrumented files
22 | extensionTestsPath = path.resolve(__dirname, '../../out-cov/test/suite/index');
23 |
24 | // signal that the coverage data should be gathered
25 | process.env['GENERATE_COVERAGE'] = '1';
26 | }
27 |
28 | // Download VS Code, unzip it and run the integration test
29 | await runTests({
30 | extensionDevelopmentPath,
31 | extensionTestsPath,
32 | launchArgs: [
33 | './testworkspace',
34 | '--disable-extensions',
35 | // '${workspaceFolder}/testworkspace'
36 | ],
37 | });
38 | } catch (err) {
39 | console.error('Failed to run tests');
40 | process.exit(1);
41 | }
42 | }
43 |
44 | main();
45 |
--------------------------------------------------------------------------------
/src/test/suite/basic.test.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as assert from 'assert';
3 | import {
4 | IPeacockSettings,
5 | ICommand,
6 | Commands,
7 | IConfiguration,
8 | StandardSettings,
9 | extensionShortName,
10 | AffectedSettings,
11 | getExtension,
12 | timeout,
13 | } from '../../models';
14 | import { setupTestSuite, teardownTestSuite, setupTest } from './lib/setup-teardown-test-suite';
15 |
16 | suite('Basic Extension Tests', () => {
17 | const originalValues = {} as IPeacockSettings;
18 | let extension: vscode.Extension;
19 |
20 | suiteSetup(async () => await setupTestSuite(originalValues));
21 | suiteTeardown(async () => await teardownTestSuite(originalValues));
22 | setup(async () => await setupTest());
23 |
24 | suiteSetup(() => {
25 | extension = getExtension() as vscode.Extension;
26 | });
27 |
28 | test('Sample Test', async () => {
29 | assert.equal(-1, [1, 2, 3].indexOf(5));
30 | });
31 |
32 | test('Activation test', async () => {
33 | await extension.activate();
34 | assert.equal(extension.isActive, true);
35 | });
36 |
37 | test('Extension loads in VSCode and is active', async () => {
38 | // Hopefully a timeout will allow the extension to activate within Windows
39 | // otherwise we get a false result.
40 | // let extension = getExtension() as vscode.Extension;
41 |
42 | await timeout(3000);
43 | assert.equal(extension.isActive, true);
44 | });
45 |
46 | test('Commands exist in package.json', () => {
47 | // let extension = getExtension() as vscode.Extension;
48 | const commandCollection: ICommand[] = extension.packageJSON.contributes.commands;
49 | const indexedCommands: { [idx: string]: Commands } = Commands as any;
50 | for (const command in Commands) {
51 | const result = commandCollection.some(c => c.command === indexedCommands[command]);
52 | assert.ok(result);
53 | }
54 | });
55 |
56 | test('Settings exist in package.json', () => {
57 | // let extension = getExtension() as vscode.Extension;
58 |
59 | const config: IConfiguration = extension.packageJSON.contributes.configuration;
60 | const properties = Object.keys(config.properties);
61 | const indexedSettings: { [idx: string]: StandardSettings } = StandardSettings as any;
62 | for (const setting in StandardSettings) {
63 | const result = properties.some(
64 | property => property === `${extensionShortName}.${indexedSettings[setting]}`,
65 | );
66 | assert.ok(result);
67 | }
68 | });
69 |
70 | test('AffectedSettings exist in package.json', () => {
71 | // let extension = getExtension() as vscode.Extension;
72 | const config: IConfiguration = extension.packageJSON.contributes.configuration;
73 | const properties = Object.keys(config.properties);
74 | const indexedSettings: { [idx: string]: AffectedSettings } = AffectedSettings as any;
75 | for (const setting in AffectedSettings) {
76 | const result = properties.some(
77 | property => property === `${extensionShortName}.${indexedSettings[setting]}`,
78 | );
79 | assert.ok(result);
80 | }
81 | });
82 |
83 | test('package.json commands registered in extension', done => {
84 | // let extension = getExtension() as vscode.Extension;
85 |
86 | const commandStrings: string[] = extension.packageJSON.contributes.commands.map(
87 | (c: ICommand) => c.command,
88 | );
89 |
90 | vscode.commands.getCommands(true).then((allCommands: string[]) => {
91 | const commands = allCommands.filter(c => c.startsWith(`${extensionShortName}.`));
92 | commands.forEach(command => {
93 | const result = commandStrings.some(c => c === command);
94 | assert.ok(result);
95 | });
96 | done();
97 | });
98 | });
99 | });
100 |
--------------------------------------------------------------------------------
/src/test/suite/built-in-colors.test.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as assert from 'assert';
3 | import {
4 | Commands,
5 | ColorSettings,
6 | IPeacockSettings,
7 | peacockGreen,
8 | StandardSettings,
9 | } from '../../models';
10 | import { setupTestSuite, teardownTestSuite, setupTest } from './lib/setup-teardown-test-suite';
11 | import { executeCommand } from './lib/constants';
12 | import { isValidColorInput } from '../../color-library';
13 | import {
14 | getColorCustomizationConfig,
15 | updateWorkspaceConfiguration,
16 | getColorCustomizationConfigFromWorkspace,
17 | getFavoriteColors,
18 | updateSurpriseMeFromFavoritesOnly,
19 | getEnvironmentAwareColor,
20 | getPeacockWorkspace,
21 | } from '../../configuration';
22 |
23 | suite('can set color to built-in color', () => {
24 | const originalValues = {} as IPeacockSettings;
25 |
26 | suiteSetup(async () => await setupTestSuite(originalValues));
27 | suiteTeardown(async () => await teardownTestSuite(originalValues));
28 | setup(async () => await setupTest());
29 |
30 | test('can set color to Peacock Green', testChangingColorToPeacockGreen());
31 |
32 | test('can set to color and it is stored in workspace config', async () => {
33 | await executeCommand(Commands.changeColorToRandom);
34 | const config = getPeacockWorkspace();
35 | const color = config[StandardSettings.Color];
36 | assert.ok(color);
37 | assert.ok(isValidColorInput(color));
38 | });
39 |
40 | suite('can set color to Random color', () => {
41 | test('color is valid', async () => {
42 | await executeCommand(Commands.changeColorToRandom);
43 | const config = getColorCustomizationConfig();
44 | assert.ok(isValidColorInput(config[ColorSettings.titleBar_activeBackground]));
45 | });
46 |
47 | suite(
48 | 'when surpriseMeFromFavoritesOnly is true, color matches a favorite and is not chosen at random',
49 | () => {
50 | const limit = 10;
51 | for (let index = 0; index < limit; index++) {
52 | test(`test run ${index} of ${limit}`, async () => {
53 | const { values: favorites } = getFavoriteColors();
54 | await updateSurpriseMeFromFavoritesOnly(true);
55 | await executeCommand(Commands.changeColorToRandom);
56 | const color = getEnvironmentAwareColor();
57 | const match = favorites.find(item => item.value.toLowerCase === color.toLowerCase);
58 | assert.ok(
59 | match,
60 | `chosen color ${color} is not found in the favorites ${JSON.stringify(favorites)}`,
61 | );
62 | });
63 | }
64 | },
65 | );
66 | });
67 |
68 | suite('when resetting colors', () => {
69 | suiteSetup(async () => await setupTestSuite(originalValues));
70 | suiteTeardown(async () => await teardownTestSuite(originalValues));
71 | setup(async () => await setupTest());
72 |
73 | const extraSettingName = 'activityBar.border';
74 | const extraSettingValue = '#ff0';
75 | const extraSetting = { 'activityBar.border': extraSettingValue };
76 |
77 | test('leaves pre-existing colorCustomizations', async () => {
78 | await removeExtraSetting(extraSettingName);
79 | // Add one non Peacock setting
80 | await updateWorkspaceConfiguration(extraSetting);
81 |
82 | await executeCommand(Commands.resetWorkspaceColors);
83 | const config = getColorCustomizationConfig();
84 | assert.equal(config[extraSettingName], extraSettingValue);
85 | assert.ok(!config[ColorSettings.titleBar_activeBackground]);
86 | assert.ok(!config[ColorSettings.statusBar_background]);
87 | assert.ok(!config[ColorSettings.activityBar_background]);
88 | assert.ok(!config[ColorSettings.activityBar_activeBackground]);
89 |
90 | await removeExtraSetting(extraSettingName);
91 | });
92 |
93 | test('removes colorCustomizations if the object is empty', async () => {
94 | await executeCommand(Commands.resetWorkspaceColors);
95 | const config = getColorCustomizationConfig();
96 | assert.ok(!config[ColorSettings.titleBar_activeBackground]);
97 | assert.ok(!config[ColorSettings.statusBar_background]);
98 | assert.ok(!config[ColorSettings.activityBar_background]);
99 | assert.ok(!config[ColorSettings.activityBar_activeBackground]);
100 | // assert.ok(!config[ColorSettings.activityBar_activeBorder]);
101 | });
102 |
103 | test('removes peacockColor', async () => {
104 | await executeCommand(Commands.resetWorkspaceColors);
105 | const config = getPeacockWorkspace();
106 | assert.ok(!config[StandardSettings.Color]);
107 | });
108 |
109 | test('removes peacockRemoteColor', async () => {
110 | await executeCommand(Commands.resetWorkspaceColors);
111 | const config = getPeacockWorkspace();
112 | assert.ok(!config[StandardSettings.RemoteColor]);
113 | });
114 | });
115 | });
116 |
117 | function testChangingColorToPeacockGreen():
118 | | ((this: Mocha.ITestCallbackContext, done: MochaDone) => any)
119 | | undefined {
120 | return testBuiltInColor(Commands.changeColorToPeacockGreen, peacockGreen);
121 | }
122 |
123 | function testBuiltInColor(
124 | cmd: Commands,
125 | builtInColor: string,
126 | ): ((this: Mocha.ITestCallbackContext, done: MochaDone) => any) | undefined {
127 | return async () => {
128 | await vscode.commands.executeCommand(cmd);
129 | const config = getColorCustomizationConfig();
130 | assert.equal(builtInColor, config[ColorSettings.titleBar_activeBackground]);
131 | };
132 | }
133 |
134 | async function removeExtraSetting(extraSettingName: string) {
135 | const newColorCustomizations: any = {
136 | ...getColorCustomizationConfigFromWorkspace(),
137 | };
138 | delete newColorCustomizations[extraSettingName];
139 | await updateWorkspaceConfiguration(newColorCustomizations);
140 | }
141 |
--------------------------------------------------------------------------------
/src/test/suite/color-input.test.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as assert from 'assert';
3 | import * as sinon from 'sinon';
4 | import { ColorSettings, Commands, IPeacockSettings } from '../../models';
5 | import { isValidColorInput } from '../../color-library';
6 | import { setupTestSuite, teardownTestSuite, setupTest } from './lib/setup-teardown-test-suite';
7 | import { executeCommand } from './lib/constants';
8 | import { getColorCustomizationConfig } from '../../configuration';
9 |
10 | suite('Enter color', () => {
11 | const originalValues = {} as IPeacockSettings;
12 |
13 | suiteSetup(async () => await setupTestSuite(originalValues));
14 | suiteTeardown(async () => await teardownTestSuite(originalValues));
15 | setup(async () => await setupTest());
16 |
17 | suite('Invalid values do nothing', () => {
18 | test('can hit ESC with no error', createColorInputTest('', undefined));
19 |
20 | test('can hit ENTER with no error', createColorInputTest('', undefined));
21 | });
22 |
23 | suite('Hex, Hex RGBA', () => {
24 | test('can set color using short hex user input', createColorInputTest('#000', '#000000'));
25 |
26 | test(
27 | 'can set color using short hex user input without hash',
28 | createColorInputTest('000', '#000000'),
29 | );
30 |
31 | test(
32 | 'can set color using short RGBA hex user input',
33 | createColorInputTest('#369C', '#336699cc'),
34 | );
35 |
36 | test(
37 | 'can set color using short RGBA hex user input without hash',
38 | createColorInputTest('369C', '#336699cc'),
39 | );
40 |
41 | test('can set color using hex user input', createColorInputTest('#f0f0f6', '#f0f0f6'));
42 |
43 | test(
44 | 'can set color using hex user input without hash',
45 | createColorInputTest('f0f0f6', '#f0f0f6'),
46 | );
47 |
48 | test('can set color using RGBA hex user input', createColorInputTest('#f0f0f688', '#f0f0f688'));
49 |
50 | test(
51 | 'can set color using RGBA hex user input without hash',
52 | createColorInputTest('f0f0f688', '#f0f0f688'),
53 | );
54 | });
55 |
56 | suite('Named colors', () => {
57 | test(
58 | 'can set color using named color user input',
59 | createColorInputTest('blanchedalmond', '#ffebcd'),
60 | );
61 |
62 | test(
63 | 'can set color using named color user input with any casing',
64 | createColorInputTest('DarkBlue', '#00008b'),
65 | );
66 |
67 | // RGB, RGBA
68 |
69 | test(
70 | 'can set color using rgb() color user input',
71 | createColorInputTest('rgb (255 0 0)', '#ff0000'),
72 | );
73 |
74 | test(
75 | 'can set color using rgb() color user input without parentheses',
76 | createColorInputTest('rgb 255 0 0', '#ff0000'),
77 | );
78 |
79 | test(
80 | 'can set color using rgba() color user input',
81 | createColorInputTest('rgba (255, 0, 0, .5)', '#ff000080'),
82 | );
83 |
84 | test(
85 | 'can set color using rgb() color user input with decimals or percentages',
86 | createColorInputTest('rgb (100% 255 0)', '#ffff00'),
87 | );
88 | });
89 |
90 | suite('HSL, HSLA', () => {
91 | test(
92 | 'can set color using hsl() color user input',
93 | createColorInputTest('hsl (0 100% 50%)', '#ff0000'),
94 | );
95 |
96 | test(
97 | 'can set color using hsl() color user input without parentheses',
98 | createColorInputTest('hsl 0 100% 50%', '#ff0000'),
99 | );
100 |
101 | test(
102 | 'can set color using hsla() color user input',
103 | createColorInputTest('hsla (0, 100%, 50%, .5)', '#ff000080'),
104 | );
105 |
106 | test(
107 | 'can set color using hsl() color user input with decimals or percentages',
108 | createColorInputTest('hsl (0, 100%, .5)', '#ff0000'),
109 | );
110 | });
111 |
112 | suite('HSV, HSVA', () => {
113 | test(
114 | 'can set color using hsv() color user input',
115 | createColorInputTest('hsv (0, 100%, 100%)', '#ff0000'),
116 | );
117 |
118 | test(
119 | 'can set color using hsv() color user input without parentheses',
120 | createColorInputTest('hsv 0 100% 100%', '#ff0000'),
121 | );
122 |
123 | test(
124 | 'can set color using hsva() color user input',
125 | createColorInputTest('hsva (0, 100%, 100%, .5)', '#ff000080'),
126 | );
127 |
128 | test(
129 | 'can set color using hsv() color user input with decimals or percentages',
130 | createColorInputTest('hsv (0, 1, 100%)', '#ff0000'),
131 | );
132 | });
133 |
134 | suite('With Parameters', () => {
135 | test(
136 | 'can set valid color using command parameters programmatically',
137 | createColorInputTestWithParam('#c0c0c0', '#c0c0c0'),
138 | );
139 |
140 | test(
141 | 'cannot set invalid color using command parameters programmatically',
142 | createColorInputTestWithParamThatThrowsError('invalid'),
143 | );
144 | });
145 | });
146 |
147 | function createColorInputTest(fakeResponse: string, expectedValue: string | undefined) {
148 | return async () => {
149 | // Stub the async input box to return a response
150 | const stub = await sinon
151 | .stub(vscode.window, 'showInputBox')
152 | .returns(Promise.resolve(fakeResponse));
153 |
154 | // fire the command
155 | await executeCommand(Commands.enterColor);
156 | const config = getColorCustomizationConfig();
157 | const value = config[ColorSettings.titleBar_activeBackground];
158 | stub.restore();
159 |
160 | // undefined is OK, since that means they hit ESC or blank
161 | // Otherwise, we need a valid color
162 | assert.ok(!value || isValidColorInput(value));
163 | assert.equal(expectedValue, value);
164 | };
165 | }
166 |
167 | function createColorInputTestWithParam(fakeResponse: string, expectedValue: string | undefined) {
168 | return async () => {
169 | await executeCommand(Commands.enterColor, fakeResponse);
170 |
171 | const config = getColorCustomizationConfig();
172 | const value = config[ColorSettings.titleBar_activeBackground];
173 |
174 | // undefined is OK, since that means they hit ESC or blank
175 | // Otherwise, we need a valid color
176 | assert.ok(!value || isValidColorInput(value));
177 | assert.equal(expectedValue, value);
178 | };
179 | }
180 |
181 | function createColorInputTestWithParamThatThrowsError(fakeResponse: string) {
182 | return async () => {
183 | assert.rejects(async () => await executeCommand(Commands.enterColor, fakeResponse), Error);
184 | const config = getColorCustomizationConfig();
185 | const value = config[ColorSettings.titleBar_activeBackground];
186 | // The value should be undefined when invalid color is set
187 | assert.ok(!value);
188 | };
189 | }
190 |
--------------------------------------------------------------------------------
/src/test/suite/config-changes.test.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as assert from 'assert';
3 | import {
4 | Commands,
5 | IPeacockSettings,
6 | AffectedSettings,
7 | IElementColors,
8 | ElementNames,
9 | IPeacockAffectedElementSettings,
10 | timeout,
11 | } from '../../models';
12 | import { setupTestSuite, teardownTestSuite, setupTest } from './lib/setup-teardown-test-suite';
13 | import { executeCommand } from './lib/constants';
14 | import {
15 | getColorCustomizationConfigFromWorkspace,
16 | getOriginalColorsForAllElements,
17 | getUserConfig,
18 | updateAffectedElements,
19 | updateGlobalConfiguration,
20 | updateWorkspaceConfiguration,
21 | } from '../../configuration';
22 |
23 | const delayInMs = 500;
24 |
25 | suite('changes to configuration', () => {
26 | const originalValues = {} as IPeacockSettings;
27 |
28 | suiteSetup(async () => await setupTestSuite(originalValues));
29 | suiteTeardown(async () => await teardownTestSuite(originalValues));
30 | setup(async () => await setupTest());
31 |
32 | setup(async () => {
33 | // This suite's tests flips these switches a lot,
34 | // so we reset before each test just to be sure.
35 | await executeCommand(Commands.resetWorkspaceColors);
36 | // Set the test values
37 | await updateAffectedElements({
38 | statusBar: true,
39 | activityBar: true,
40 | titleBar: true,
41 | } as IPeacockAffectedElementSettings);
42 | });
43 |
44 | suite('when starting with no colors in the workspace config', () => {
45 | test('have no effect', async () => {
46 | const colors1: IElementColors = getOriginalColorsForAllElements();
47 | const config1 = getUserConfig();
48 | await updateGlobalConfiguration(
49 | AffectedSettings.ActivityBar,
50 | !config1[AffectedSettings.ActivityBar],
51 | );
52 |
53 | await timeout(delayInMs);
54 |
55 | const colors2: IElementColors = getOriginalColorsForAllElements();
56 | assert.ok(colors1[ElementNames.activityBar] === colors2[ElementNames.activityBar]);
57 | assert.ok(
58 | !!config1[AffectedSettings.StatusBar] &&
59 | colors1[ElementNames.statusBar] === colors2[ElementNames.statusBar],
60 | );
61 | assert.ok(
62 | !!config1[AffectedSettings.TitleBar] &&
63 | colors1[ElementNames.titleBar] === colors2[ElementNames.titleBar],
64 | );
65 | });
66 | });
67 |
68 | suite('when starting with a color in the workspace config', () => {
69 | setup(async () => {
70 | // Use Peacock Green as the color the instance began with
71 | await vscode.commands.executeCommand(Commands.changeColorToPeacockGreen);
72 | });
73 |
74 | test('will change color when unselecting activitybar', async () => {
75 | const colorsBefore: IElementColors = getOriginalColorsForAllElements();
76 | const configBefore = getUserConfig();
77 | await updateGlobalConfiguration(AffectedSettings.ActivityBar, false);
78 |
79 | await timeout(delayInMs);
80 |
81 | const colorsAfter: IElementColors = getOriginalColorsForAllElements();
82 | assert.ok(colorsBefore[ElementNames.activityBar] !== colorsAfter[ElementNames.activityBar]);
83 | assert.ok(
84 | !!configBefore[AffectedSettings.StatusBar] &&
85 | colorsBefore[ElementNames.statusBar] === colorsAfter[ElementNames.statusBar],
86 | );
87 | assert.ok(
88 | !!configBefore[AffectedSettings.TitleBar] &&
89 | colorsBefore[ElementNames.titleBar] === colorsAfter[ElementNames.titleBar],
90 | );
91 | });
92 |
93 | test('will change color when unselecting statusbar', async () => {
94 | const colors1: IElementColors = getOriginalColorsForAllElements();
95 | const config1 = getUserConfig();
96 | await updateGlobalConfiguration(
97 | AffectedSettings.StatusBar,
98 | !config1[AffectedSettings.StatusBar],
99 | );
100 |
101 | await timeout(delayInMs);
102 |
103 | const colors2: IElementColors = getOriginalColorsForAllElements();
104 | assert.ok(colors1[ElementNames.statusBar] !== colors2[ElementNames.statusBar]);
105 | assert.ok(
106 | !!config1[AffectedSettings.ActivityBar] &&
107 | colors1[ElementNames.activityBar] === colors2[ElementNames.activityBar],
108 | );
109 | assert.ok(
110 | !!config1[AffectedSettings.TitleBar] &&
111 | colors1[ElementNames.titleBar] === colors2[ElementNames.titleBar],
112 | );
113 | });
114 |
115 | test('will change color when unselecting titlebar', async () => {
116 | const config1 = getUserConfig();
117 | const colors1: IElementColors = getOriginalColorsForAllElements();
118 | await updateGlobalConfiguration(
119 | AffectedSettings.TitleBar,
120 | !config1[AffectedSettings.TitleBar],
121 | );
122 |
123 | await timeout(delayInMs);
124 | const colors2: IElementColors = getOriginalColorsForAllElements();
125 | assert.ok(colors1[ElementNames.titleBar] !== colors2[ElementNames.titleBar]);
126 | assert.ok(
127 | !!config1[AffectedSettings.ActivityBar] &&
128 | colors1[ElementNames.activityBar] === colors2[ElementNames.activityBar],
129 | );
130 | assert.ok(
131 | !!config1[AffectedSettings.StatusBar] &&
132 | colors1[ElementNames.statusBar] === colors2[ElementNames.statusBar],
133 | );
134 | });
135 |
136 | test('will preserve setting order', async () => {
137 | const originalCustomizations = getColorCustomizationConfigFromWorkspace();
138 | const keptKeys = Object.keys(originalCustomizations).filter((_, i) => i % 2);
139 | const removedKeys = Object.keys(originalCustomizations).filter((_, i) => ~i % 2);
140 | removedKeys.forEach(r => delete originalCustomizations[r]);
141 | await updateWorkspaceConfiguration(originalCustomizations);
142 |
143 | await executeCommand(Commands.changeColorToPeacockGreen);
144 |
145 | const updatedCustomizations = getColorCustomizationConfigFromWorkspace();
146 |
147 | assert.deepEqual(
148 | Object.keys(updatedCustomizations),
149 | keptKeys.concat(removedKeys),
150 | 'existing setting order was not preserved',
151 | );
152 | });
153 | });
154 | });
155 |
--------------------------------------------------------------------------------
/src/test/suite/current-color.test.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as sinon from 'sinon';
3 | import * as assert from 'assert';
4 | import { IPeacockSettings, Commands, peacockGreen, azureBlue } from '../../models';
5 | import { setupTestSuite, teardownTestSuite, setupTest } from './lib/setup-teardown-test-suite';
6 | import { executeCommand } from './lib/constants';
7 | import { getEnvironmentAwareColor } from '../../configuration';
8 |
9 | suite('Current Color Tests', () => {
10 | const originalValues = {} as IPeacockSettings;
11 |
12 | suiteSetup(async () => await setupTestSuite(originalValues));
13 | suiteTeardown(async () => await teardownTestSuite(originalValues));
14 | setup(async () => await setupTest());
15 |
16 | suite('when running the "show color" command', async () => {
17 | test('Shows the current color', async () => {
18 | await executeCommand(Commands.changeColorToPeacockGreen);
19 | await executeCommand(Commands.showAndCopyCurrentColor);
20 | const color = getEnvironmentAwareColor();
21 | assert.equal(color, peacockGreen);
22 | });
23 | test('Shows the current color when it is a custom color', async () => {
24 | const fakeResponse = `Azure Blue -> ${azureBlue}`;
25 | const stub = await sinon
26 | .stub(vscode.window, 'showQuickPick')
27 | .returns(Promise.resolve(fakeResponse));
28 |
29 | await executeCommand(Commands.changeColorToFavorite);
30 | const color = getEnvironmentAwareColor();
31 | stub.restore();
32 |
33 | await executeCommand(Commands.showAndCopyCurrentColor);
34 | assert.equal(color, azureBlue);
35 | });
36 | test('Shows no color when none is set', async () => {
37 | await executeCommand(Commands.showAndCopyCurrentColor);
38 | const color = getEnvironmentAwareColor();
39 | assert.equal(color, '');
40 | });
41 | test('Copies to the clipboard', async () => {
42 | await executeCommand(Commands.changeColorToPeacockGreen);
43 | await executeCommand(Commands.showAndCopyCurrentColor);
44 | const clipboardColor = await vscode.env.clipboard.readText();
45 | assert.equal(clipboardColor, peacockGreen);
46 | });
47 | });
48 | });
49 |
--------------------------------------------------------------------------------
/src/test/suite/darken-lighten.test.ts:
--------------------------------------------------------------------------------
1 | import * as assert from 'assert';
2 | import { IPeacockSettings, Commands, ColorSettings, peacockGreen } from '../../models';
3 | import { setupTestSuite, teardownTestSuite, setupTest } from './lib/setup-teardown-test-suite';
4 | import { getColorCustomizationConfig, getDarkenLightenPercentage } from '../../configuration';
5 | import { executeCommand } from './lib/constants';
6 | import { getLightenedColorHex, getDarkenedColorHex } from '../../color-library';
7 |
8 | suite('Darken/Lighten commands', () => {
9 | const originalValues = {} as IPeacockSettings;
10 |
11 | suiteSetup(async () => await setupTestSuite(originalValues));
12 | suiteTeardown(async () => await teardownTestSuite(originalValues));
13 | setup(async () => await setupTest());
14 |
15 | test('can lighten a color', async () => {
16 | await executeCommand(Commands.changeColorToPeacockGreen);
17 | await executeCommand(Commands.lighten);
18 | const config = getColorCustomizationConfig();
19 | const pct = getDarkenLightenPercentage();
20 |
21 | assert.equal(
22 | getLightenedColorHex(peacockGreen, pct),
23 | config[ColorSettings.activityBar_background],
24 | );
25 | });
26 |
27 | test('can darken a color', async () => {
28 | await executeCommand(Commands.changeColorToPeacockGreen);
29 | await executeCommand(Commands.darken);
30 | const config = getColorCustomizationConfig();
31 | const pct = getDarkenLightenPercentage();
32 |
33 | assert.equal(
34 | getDarkenedColorHex(peacockGreen, pct),
35 | config[ColorSettings.activityBar_background],
36 | );
37 | });
38 | });
39 |
--------------------------------------------------------------------------------
/src/test/suite/documentation.test.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as sinon from 'sinon';
3 | import * as assert from 'assert';
4 | import { IPeacockSettings, Commands, docsUri } from '../../models';
5 | import { setupTestSuite, teardownTestSuite, setupTest } from './lib/setup-teardown-test-suite';
6 | import { executeCommand } from './lib/constants';
7 |
8 | suite('Documentation Tests', () => {
9 | const originalValues = {} as IPeacockSettings;
10 |
11 | suiteSetup(async () => await setupTestSuite(originalValues));
12 | suiteTeardown(async () => await teardownTestSuite(originalValues));
13 | setup(async () => await setupTest());
14 |
15 | // suiteSetup(async () => {});
16 |
17 | test('can open documentation web site in a browser', async () => {
18 | const openExternalStub = sinon.stub(vscode.env, 'openExternal');
19 |
20 | // Call the function to test.
21 | await executeCommand(Commands.showDocumentation);
22 |
23 | // Ensure it attempted to open the browser.
24 | assert.ok(openExternalStub.calledOnce);
25 | assert.ok(openExternalStub.calledOnceWithExactly(docsUri), 'wrong Uri was opened');
26 | const wrongUri = vscode.Uri.parse('https://google.com');
27 | assert.ok(!openExternalStub.calledOnceWithExactly(wrongUri));
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/src/test/suite/element-adjustments.test.ts:
--------------------------------------------------------------------------------
1 | import * as assert from 'assert';
2 | import {
3 | IPeacockSettings,
4 | IPeacockElementAdjustments,
5 | Commands,
6 | ColorSettings,
7 | IPeacockAffectedElementSettings,
8 | peacockGreen,
9 | } from '../../models';
10 | import { setupTestSuite, teardownTestSuite, setupTest } from './lib/setup-teardown-test-suite';
11 | import {
12 | updateElementAdjustments,
13 | getColorCustomizationConfig,
14 | updateAffectedElements,
15 | } from '../../configuration';
16 | import { executeCommand, allAffectedElements } from './lib/constants';
17 | import { getLightenedColorHex, getDarkenedColorHex, getColorBrightness } from '../../color-library';
18 |
19 | suite('Element adjustments', () => {
20 | const originalValues = {} as IPeacockSettings;
21 |
22 | suiteSetup(async () => await setupTestSuite(originalValues));
23 | suiteTeardown(async () => await teardownTestSuite(originalValues));
24 | setup(async () => await setupTest());
25 |
26 | const elementAdjustments: IPeacockElementAdjustments = {
27 | activityBar: 'lighten',
28 | statusBar: 'darken',
29 | titleBar: 'none',
30 | };
31 |
32 | suiteSetup(async () => {
33 | await updateElementAdjustments(elementAdjustments);
34 | });
35 |
36 | test('can lighten the color of an affected element', async () => {
37 | await executeCommand(Commands.changeColorToPeacockGreen);
38 | const config = getColorCustomizationConfig();
39 | assert.equal(getLightenedColorHex(peacockGreen), config[ColorSettings.activityBar_background]);
40 | });
41 |
42 | test('can darken the color of an affected element', async () => {
43 | await executeCommand(Commands.changeColorToPeacockGreen);
44 | const config = getColorCustomizationConfig();
45 | assert.equal(getDarkenedColorHex(peacockGreen), config[ColorSettings.statusBar_background]);
46 | });
47 |
48 | test('set adjustment to none for an affected element is noop', async () => {
49 | await executeCommand(Commands.changeColorToPeacockGreen);
50 | const config = getColorCustomizationConfig();
51 | assert.equal(peacockGreen, config[ColorSettings.titleBar_activeBackground]);
52 | });
53 |
54 | test('set adjustment to lighten for an affected element is lighter color', async () => {
55 | await executeCommand(Commands.changeColorToPeacockGreen);
56 | const config = getColorCustomizationConfig();
57 |
58 | const originalBrightness = getColorBrightness(peacockGreen);
59 | const adjustedBrightness = getColorBrightness(config[ColorSettings.activityBar_background]);
60 | assert.ok(
61 | originalBrightness < adjustedBrightness,
62 | `Expected original brightness ${originalBrightness} to be less than ${adjustedBrightness}, but was greater`,
63 | );
64 | });
65 |
66 | test('set adjustment to darken for an affected element is darker color', async () => {
67 | await executeCommand(Commands.changeColorToPeacockGreen);
68 | const config = getColorCustomizationConfig();
69 |
70 | const originalBrightness = getColorBrightness(peacockGreen);
71 | const adjustedBrightness = getColorBrightness(config[ColorSettings.statusBar_background]);
72 | assert.ok(
73 | originalBrightness > adjustedBrightness,
74 | `Expected original brightness ${originalBrightness} to be greater than ${adjustedBrightness}, but was less`,
75 | );
76 | });
77 |
78 | test('can adjust the color of an affected elements independently', async () => {
79 | await executeCommand(Commands.changeColorToPeacockGreen);
80 | const config = getColorCustomizationConfig();
81 | assert.equal(getLightenedColorHex(peacockGreen), config[ColorSettings.activityBar_background]);
82 | assert.equal(getDarkenedColorHex(peacockGreen), config[ColorSettings.statusBar_background]);
83 | assert.equal(peacockGreen, config[ColorSettings.titleBar_activeBackground]);
84 | });
85 |
86 | test('can only adjust the color of an element that is affected', async () => {
87 | await updateAffectedElements({
88 | activityBar: false,
89 | statusBar: true,
90 | titleBar: false,
91 | } as IPeacockAffectedElementSettings);
92 |
93 | await executeCommand(Commands.changeColorToPeacockGreen);
94 | const config = getColorCustomizationConfig();
95 |
96 | assert.equal(getDarkenedColorHex(peacockGreen), config[ColorSettings.statusBar_background]);
97 | assert.ok(!config[ColorSettings.activityBar_background]);
98 | assert.ok(!config[ColorSettings.titleBar_activeBackground]);
99 |
100 | await updateAffectedElements(allAffectedElements);
101 | });
102 | });
103 |
--------------------------------------------------------------------------------
/src/test/suite/favorite-colors.test.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as sinon from 'sinon';
3 | import * as assert from 'assert';
4 | import { IPeacockSettings, Commands, azureBlue } from '../../models';
5 | import { setupTestSuite, teardownTestSuite, setupTest } from './lib/setup-teardown-test-suite';
6 | import { parseFavoriteColorValue } from '../../inputs';
7 | import { isValidColorInput } from '../../color-library';
8 | import { executeCommand } from './lib/constants';
9 | import {
10 | getFavoriteColors,
11 | updateFavoriteColors,
12 | getEnvironmentAwareColor,
13 | } from '../../configuration';
14 |
15 | suite('Favorite colors', () => {
16 | const originalValues = {} as IPeacockSettings;
17 |
18 | suiteSetup(async () => await setupTestSuite(originalValues));
19 | suiteTeardown(async () => await teardownTestSuite(originalValues));
20 | setup(async () => await setupTest());
21 |
22 | test('can set color to favorite color', async () => {
23 | // Stub the async quick pick to return a response
24 | const fakeResponse = `Azure Blue -> ${azureBlue}`;
25 | const stub = await sinon
26 | .stub(vscode.window, 'showQuickPick')
27 | .returns(Promise.resolve(fakeResponse));
28 |
29 | await executeCommand(Commands.changeColorToFavorite);
30 | const color = getEnvironmentAwareColor();
31 | stub.restore();
32 |
33 | const parsedResponse = parseFavoriteColorValue(fakeResponse);
34 |
35 | assert.ok(isValidColorInput(color));
36 | assert.ok(color === parsedResponse);
37 | });
38 |
39 | test('set to favorite color with no preferences is a noop', async () => {
40 | // set the color to peacock green to start
41 | await executeCommand(Commands.changeColorToPeacockGreen);
42 |
43 | // Stub the async quick pick to return a response
44 | const fakeResponse = '';
45 | const stub = await sinon
46 | .stub(vscode.window, 'showQuickPick')
47 | .returns(Promise.resolve(fakeResponse));
48 |
49 | const valueBefore = getEnvironmentAwareColor();
50 | await executeCommand(Commands.changeColorToFavorite);
51 | const valueAfter = getEnvironmentAwareColor();
52 | stub.restore();
53 |
54 | assert.ok(valueBefore === valueAfter);
55 | });
56 |
57 | test('set to favorite color with no preferences is a noop, when color was not previously set', async () => {
58 | // Stub the async quick pick to return a response
59 | const fakeResponse = '';
60 | const stub = await sinon
61 | .stub(vscode.window, 'showQuickPick')
62 | .returns(Promise.resolve(fakeResponse));
63 |
64 | const colorBefore = getEnvironmentAwareColor();
65 | await executeCommand(Commands.changeColorToFavorite);
66 | const colorAfter = getEnvironmentAwareColor();
67 | stub.restore();
68 |
69 | assert.ok(!isValidColorInput(colorAfter));
70 | assert.ok(colorAfter === colorBefore);
71 | });
72 |
73 | test('set to favorite color is noop when there are no favorites ', async () => {
74 | // set the color to peacock green to start
75 | await executeCommand(Commands.changeColorToPeacockGreen);
76 |
77 | // Stub the async quick pick to return a response
78 | const fakeResponse = '';
79 | const stub = await sinon
80 | .stub(vscode.window, 'showQuickPick')
81 | .returns(Promise.resolve(fakeResponse));
82 |
83 | // Save favorites
84 | const { values: favoriteColors } = getFavoriteColors();
85 | originalValues.favoriteColors = favoriteColors;
86 | // Remove favorites
87 | await updateFavoriteColors([]);
88 |
89 | const colorBefore = getEnvironmentAwareColor();
90 | await executeCommand(Commands.changeColorToFavorite);
91 | const colorAfter = getEnvironmentAwareColor();
92 | stub.restore();
93 |
94 | // Put back original favorites
95 | await updateFavoriteColors(originalValues.favoriteColors);
96 |
97 | assert.ok(colorBefore && colorAfter);
98 | assert.ok(isValidColorInput(colorAfter), `${colorAfter} is not a valid color`);
99 | assert.ok(colorBefore === colorAfter);
100 | });
101 | });
102 |
--------------------------------------------------------------------------------
/src/test/suite/foreground.test.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as sinon from 'sinon';
3 | import * as assert from 'assert';
4 | import { IPeacockSettings, Commands, ColorSettings } from '../../models';
5 | import { setupTestSuite, teardownTestSuite } from './lib/setup-teardown-test-suite';
6 | import { isValidColorInput } from '../../color-library';
7 | import { executeCommand } from './lib/constants';
8 | import {
9 | getColorCustomizationConfig,
10 | getLightForegroundColorOrOverride,
11 | getDarkForegroundColorOrOverride,
12 | } from '../../configuration';
13 |
14 | suite('Foreground color', () => {
15 | const originalValues = {} as IPeacockSettings;
16 |
17 | suiteSetup(async () => {
18 | await setupTestSuite(originalValues);
19 | });
20 |
21 | suiteTeardown(() => teardownTestSuite(originalValues));
22 |
23 | setup(async () => {
24 | await executeCommand(Commands.resetWorkspaceColors);
25 | });
26 |
27 | test(
28 | 'is set to light foreground on black backgrounds',
29 | createForegroundTest('hsl (0, 0, 0)', getLightForegroundColorOrOverride()),
30 | );
31 |
32 | test(
33 | 'is set to light foreground on dark backgrounds',
34 | createForegroundTest('hsl (0, 0, 25%)', getLightForegroundColorOrOverride()),
35 | );
36 |
37 | test(
38 | 'is set to light foreground on less than 50% bright backgrounds',
39 | createForegroundTest('hsl (0, 0, 49%)', getLightForegroundColorOrOverride()),
40 | );
41 |
42 | test(
43 | 'is set to dark foreground on greater than or equal to 50% bright backgrounds',
44 | createForegroundTest('hsl (0, 0, 50%)', getDarkForegroundColorOrOverride()),
45 | );
46 |
47 | test(
48 | 'is set to dark foreground on light backgrounds',
49 | createForegroundTest('hsl (0, 0, 75%)', getDarkForegroundColorOrOverride()),
50 | );
51 |
52 | test(
53 | 'is set to dark foreground on white backgrounds',
54 | createForegroundTest('hsl (0, 100%, 100%)', getDarkForegroundColorOrOverride()),
55 | );
56 | });
57 |
58 | function createForegroundTest(fakeResponse: string, expectedValue: string) {
59 | return async () => {
60 | // Stub the async input box to return a response
61 | const stub = await sinon
62 | .stub(vscode.window, 'showInputBox')
63 | .returns(Promise.resolve(fakeResponse));
64 |
65 | // fire the command
66 | await executeCommand(Commands.enterColor);
67 | const config = getColorCustomizationConfig();
68 | const value = config[ColorSettings.activityBar_foreground];
69 | stub.restore();
70 |
71 | assert.ok(isValidColorInput(value));
72 | assert.equal(expectedValue, value);
73 | };
74 | }
75 |
--------------------------------------------------------------------------------
/src/test/suite/index.ts:
--------------------------------------------------------------------------------
1 | import * as path from 'path';
2 | import * as Mocha from 'mocha';
3 | import * as glob from 'glob';
4 | import { createReport } from '../coverage';
5 |
6 | export function run(): Promise {
7 | // Create the mocha test
8 | const mocha = new Mocha({
9 | ui: 'tdd',
10 | //----------------------------------------
11 | // Stuff from old test setup
12 | timeout: 7500, // longer timeout, in case
13 | // useColors: true, // colored output from test results
14 | //----------------------------------------
15 | reporter: 'mocha-multi-reporters',
16 | reporterOptions: {
17 | reporterEnabled: 'spec, xunit',
18 | xunitReporterOptions: {
19 | output: path.join(__dirname, '..', '..', 'test-results.xml'),
20 | },
21 | },
22 | });
23 | // mocha.useColors(true);
24 |
25 | const testsRoot = path.resolve(__dirname, '..');
26 |
27 | return new Promise((c, e) => {
28 | glob('**/**.test.js', { cwd: testsRoot }, (err: any, files: any) => {
29 | if (err) {
30 | return e(err);
31 | }
32 |
33 | // Add files to the test suite
34 | files.forEach((f: any) => mocha.addFile(path.resolve(testsRoot, f)));
35 |
36 | try {
37 | // Run the mocha test
38 | mocha.run(failures => {
39 | if (failures > 0) {
40 | e(new Error(`${failures} tests failed.`));
41 | } else {
42 | c();
43 | }
44 | });
45 | } catch (err) {
46 | e(err);
47 | }
48 | });
49 | }).then(() => {
50 | // Tests have finished executing, check if we should generate a coverage report
51 | if (process.env['GENERATE_COVERAGE']) {
52 | createReport();
53 | }
54 | });
55 | }
56 |
--------------------------------------------------------------------------------
/src/test/suite/lib/constants.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as sinon from 'sinon';
3 | import { IPeacockAffectedElementSettings, IPeacockElementAdjustments } from '../../../models';
4 |
5 | export const executeCommand = vscode.commands.executeCommand;
6 |
7 | export const noopElementAdjustments = {
8 | activityBar: 'none',
9 | statusBar: 'none',
10 | titleBar: 'none',
11 | } as IPeacockElementAdjustments;
12 |
13 | export const lightenActivityBarElementAdjustments = {
14 | activityBar: 'lighten',
15 | statusBar: 'none',
16 | titleBar: 'none',
17 | } as IPeacockElementAdjustments;
18 |
19 | export const allAffectedElements = {
20 | activityBar: true,
21 | statusBar: true,
22 | titleBar: true,
23 | } as IPeacockAffectedElementSettings;
24 |
25 | export const stubQuickPick = async (fakeResponse: string) =>
26 | await sinon.stub(vscode.window, 'showQuickPick').returns(Promise.resolve(fakeResponse));
27 | export const stubInputBox = async (fakeResponse: string) =>
28 | await sinon.stub(vscode.window, 'showInputBox').returns(Promise.resolve(fakeResponse));
29 |
--------------------------------------------------------------------------------
/src/test/suite/lib/setup-teardown-test-suite.ts:
--------------------------------------------------------------------------------
1 | import {
2 | IPeacockSettings,
3 | Commands,
4 | ForegroundColors,
5 | starterSetOfFavorites,
6 | getExtension,
7 | } from '../../../models';
8 | import {
9 | getAffectedElements,
10 | getFavoriteColors,
11 | updateFavoriteColors,
12 | updateElementAdjustments,
13 | updateKeepForegroundColor,
14 | getKeepForegroundColor,
15 | updateSurpriseMeOnStartup,
16 | getDarkForegroundColor,
17 | getLightForegroundColor,
18 | updateDarkForegroundColor,
19 | updateLightForegroundColor,
20 | updateAffectedElements,
21 | updateSurpriseMeFromFavoritesOnly,
22 | getSurpriseMeFromFavoritesOnly,
23 | getShowColorInStatusBar,
24 | updateShowColorInStatusBar,
25 | getPeacockColor,
26 | getPeacockRemoteColor,
27 | updatePeacockColor,
28 | updatePeacockRemoteColor,
29 | getKeepBadgeColor,
30 | updateKeepBadgeColor,
31 | } from '../../../configuration';
32 |
33 | import { noopElementAdjustments, executeCommand, allAffectedElements } from './constants';
34 |
35 | export async function setupTest() {
36 | await executeCommand(Commands.resetWorkspaceColors);
37 | }
38 |
39 | export async function setupTestSuite(
40 | // extension: vscode.Extension | undefined,
41 | originalValues: IPeacockSettings,
42 | ) {
43 | const extension = getExtension();
44 |
45 | // Save the original values
46 | originalValues.affectedElements = getAffectedElements();
47 | originalValues.keepForegroundColor = getKeepForegroundColor();
48 | const { values: favoriteColors } = getFavoriteColors();
49 | originalValues.favoriteColors = favoriteColors;
50 | originalValues.darkForegroundColor = getDarkForegroundColor();
51 | originalValues.lightForegroundColor = getLightForegroundColor();
52 | originalValues.keepBadgeColor = getKeepBadgeColor();
53 | originalValues.surpriseMeFromFavoritesOnly = getSurpriseMeFromFavoritesOnly();
54 | originalValues.showColorInStatusBar = getShowColorInStatusBar();
55 | originalValues.color = getPeacockColor();
56 | originalValues.remoteColor = getPeacockRemoteColor();
57 |
58 | // Set the test values
59 | await updateAffectedElements(allAffectedElements);
60 | await updateFavoriteColors(starterSetOfFavorites);
61 | await updateKeepForegroundColor(false);
62 | await updateSurpriseMeOnStartup(false);
63 | await updateElementAdjustments(noopElementAdjustments);
64 | await updateDarkForegroundColor(ForegroundColors.DarkForeground);
65 | await updateLightForegroundColor(ForegroundColors.LightForeground);
66 | await updateKeepBadgeColor(false);
67 | await updateSurpriseMeFromFavoritesOnly(false);
68 | await updateShowColorInStatusBar(true);
69 | await updatePeacockColor(undefined);
70 | await updatePeacockRemoteColor(undefined);
71 | return extension;
72 | }
73 |
74 | export async function teardownTestSuite(originalValues: IPeacockSettings) {
75 | await executeCommand(Commands.resetWorkspaceColors);
76 |
77 | // put back the original peacock user settings
78 |
79 | await updateAffectedElements(originalValues.affectedElements);
80 | await updateElementAdjustments(originalValues.elementAdjustments);
81 | await updateFavoriteColors(originalValues.favoriteColors);
82 | await updateKeepForegroundColor(originalValues.keepForegroundColor);
83 | await updateDarkForegroundColor(originalValues.darkForegroundColor);
84 | await updateLightForegroundColor(originalValues.lightForegroundColor);
85 | await updateKeepBadgeColor(originalValues.keepBadgeColor);
86 | await updateSurpriseMeFromFavoritesOnly(originalValues.surpriseMeFromFavoritesOnly);
87 | await updateSurpriseMeOnStartup(originalValues.surpriseMeOnStartup);
88 | await updateShowColorInStatusBar(originalValues.showColorInStatusBar);
89 | await updatePeacockColor(originalValues.color);
90 | await updatePeacockRemoteColor(originalValues.remoteColor);
91 | }
92 |
--------------------------------------------------------------------------------
/src/test/suite/notification.test.ts:
--------------------------------------------------------------------------------
1 | import * as assert from 'assert';
2 | import { IPeacockSettings } from '../../models';
3 | import { setupTestSuite, teardownTestSuite, setupTest } from './lib/setup-teardown-test-suite';
4 | import { notify } from '../../notification';
5 | import sinon = require('sinon');
6 | import { Logger } from '../../logging';
7 |
8 | suite('Notification Tests', () => {
9 | const originalValues = {} as IPeacockSettings;
10 |
11 | suiteSetup(async () => await setupTestSuite(originalValues));
12 | suiteTeardown(async () => await teardownTestSuite(originalValues));
13 | setup(async () => await setupTest());
14 |
15 | test('Can fire notification without logging', () => {
16 | const loggerStub = sinon.stub(Logger, 'info');
17 | notify('test message');
18 | assert.ok(!loggerStub.called);
19 | loggerStub.restore();
20 | });
21 |
22 | test('Can fire notification with logging', () => {
23 | const loggerStub = sinon.stub(Logger, 'info');
24 | notify('test message', true);
25 | assert.ok(loggerStub.called);
26 | loggerStub.restore();
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/src/test/suite/reset.test.ts:
--------------------------------------------------------------------------------
1 | import * as assert from 'assert';
2 | import { IPeacockSettings, ElementNames, peacockGreen, azureBlue, Commands } from '../../models';
3 | import { setupTestSuite, teardownTestSuite, setupTest } from './lib/setup-teardown-test-suite';
4 | import {
5 | getOriginalColorsForAllElements,
6 | updatePeacockColorInUserSettings,
7 | updatePeacockColor,
8 | getPeacockColor,
9 | } from '../../configuration';
10 | import { executeCommand } from './lib/constants';
11 |
12 | suite('Reset Tests', () => {
13 | const originalValues = {} as IPeacockSettings;
14 |
15 | suiteSetup(async () => await setupTestSuite(originalValues));
16 | suiteTeardown(async () => await teardownTestSuite(originalValues));
17 | setup(async () => await setupTest());
18 |
19 | suite('when resetting workspace colors', () => {
20 | test('when global color exists, workspace still has colors applied', async () => {
21 | await updatePeacockColorInUserSettings(peacockGreen);
22 | await updatePeacockColor(azureBlue);
23 |
24 | await executeCommand(Commands.resetWorkspaceColors);
25 |
26 | const color = getPeacockColor();
27 | const appliedColors = getOriginalColorsForAllElements();
28 |
29 | assert.equal(color, peacockGreen, 'Color should be equal to what is in the User Settings');
30 | assert.equal(
31 | appliedColors[ElementNames.statusBar],
32 | peacockGreen,
33 | 'Applied color should be equal to what is in the User Settings',
34 | );
35 | });
36 |
37 | test('when global color does not exist, no colors should be in the workspace color customizations', async () => {
38 | await updatePeacockColorInUserSettings(undefined);
39 | await updatePeacockColor(azureBlue);
40 |
41 | await executeCommand(Commands.resetWorkspaceColors);
42 |
43 | const color = getPeacockColor();
44 | const appliedColors = getOriginalColorsForAllElements();
45 |
46 | assert.ok(
47 | !color,
48 | 'Color should be undefined since there are no peacock.color in any settings',
49 | );
50 | assert.ok(!appliedColors[ElementNames.statusBar], 'No colors should be applied');
51 | });
52 | });
53 |
54 | test('when removing all colors, no colors nor color customizations remain', async () => {
55 | await updatePeacockColorInUserSettings(peacockGreen);
56 | await updatePeacockColor(azureBlue);
57 |
58 | await executeCommand(Commands.removeAllColors);
59 |
60 | const color = getPeacockColor();
61 | const appliedColors = getOriginalColorsForAllElements();
62 |
63 | assert.ok(!color, 'Color should be undefined since there are no peacock.color in any settings');
64 | assert.ok(!appliedColors[ElementNames.statusBar], 'No colors should be applied');
65 | });
66 | });
67 |
--------------------------------------------------------------------------------
/src/test/suite/save-favorite-color.test.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as assert from 'assert';
3 | import * as sinon from 'sinon';
4 | import { Commands, IPeacockSettings } from '../../models';
5 | import { setupTestSuite, teardownTestSuite, setupTest } from './lib/setup-teardown-test-suite';
6 | import { executeCommand, lightenActivityBarElementAdjustments } from './lib/constants';
7 | import {
8 | getFavoriteColors,
9 | updateElementAdjustments,
10 | getEnvironmentAwareColor,
11 | } from '../../configuration';
12 |
13 | const faveName = 'TEST FAVE NAME';
14 |
15 | suite('Save favorite color', () => {
16 | const originalValues = {} as IPeacockSettings;
17 | suiteSetup(async () => await setupTestSuite(originalValues));
18 | suiteTeardown(async () => await teardownTestSuite(originalValues));
19 | setup(async () => await setupTest());
20 |
21 | suiteSetup(async () => {
22 | await updateElementAdjustments(lightenActivityBarElementAdjustments);
23 | });
24 |
25 | setup(async () => {
26 | await executeCommand(Commands.changeColorToPeacockGreen);
27 | });
28 |
29 | test('with valid name successfully', async () => {
30 | // Stub the async input box to return a response
31 | const stub = await sinon.stub(vscode.window, 'showInputBox').returns(Promise.resolve(faveName));
32 |
33 | await executeCommand(Commands.saveColorToFavorites);
34 | const { values: favoriteColors } = getFavoriteColors();
35 | stub.restore();
36 |
37 | assert.ok(favoriteColors.some(f => f.name === faveName));
38 | });
39 |
40 | test('with no name should not add the favorite', async () => {
41 | const emptyName = '';
42 | // Stub the async input box to return a response
43 | const stub = await sinon
44 | .stub(vscode.window, 'showInputBox')
45 | .returns(Promise.resolve(emptyName));
46 |
47 | const { values: favoriteColorsBefore } = getFavoriteColors();
48 | await executeCommand(Commands.saveColorToFavorites);
49 | const { values: favoriteColorsAfter } = getFavoriteColors();
50 | stub.restore();
51 |
52 | assert.equal(favoriteColorsBefore.length, favoriteColorsAfter.length);
53 | assert.ok(!favoriteColorsAfter.some(f => f.name === emptyName));
54 | });
55 |
56 | test('current color does not change', async () => {
57 | // activity bar is lighter than the titlebar and statusbar
58 | // BUT the color should not change, as we should grab the color
59 | // before any adjustments are made
60 |
61 | const currentColor = getEnvironmentAwareColor();
62 |
63 | // Stub the async input box to return a response
64 | const stub = await sinon.stub(vscode.window, 'showInputBox').returns(Promise.resolve(faveName));
65 |
66 | await executeCommand(Commands.saveColorToFavorites);
67 | stub.restore();
68 |
69 | const newCurrentColor = getEnvironmentAwareColor();
70 | // console.log(`currentColor=${currentColor} and newCurrentColor = ${newCurrentColor}`);
71 |
72 | assert.equal(currentColor, newCurrentColor);
73 | });
74 | });
75 |
--------------------------------------------------------------------------------
/src/test/suite/save-starter-favorite-colors.test.ts:
--------------------------------------------------------------------------------
1 | import * as assert from 'assert';
2 | import { IPeacockSettings, Commands, starterSetOfFavorites } from '../../models';
3 | import { setupTestSuite, teardownTestSuite, setupTest } from './lib/setup-teardown-test-suite';
4 | import {
5 | getFavoriteColors,
6 | writeRecommendedFavoriteColors,
7 | updateFavoriteColors,
8 | } from '../../configuration';
9 | import { executeCommand, stubInputBox } from './lib/constants';
10 |
11 | suite('Save starter favorite colors', () => {
12 | const originalValues = {} as IPeacockSettings;
13 |
14 | suiteSetup(async () => await setupTestSuite(originalValues));
15 | suiteTeardown(async () => await teardownTestSuite(originalValues));
16 | setup(async () => await setupTest());
17 |
18 | suite('when adding recommended favorites', async () => {
19 | test('any removed ones are added back', async () => {
20 | const vueGreenName = 'Vue Green';
21 | // Start with starterSetOfFavorites, minus Vue
22 |
23 | // Remove 1 starterFaves (Vue green)
24 | const starter = starterSetOfFavorites.filter(item => item.name !== 'Vue Green');
25 | await updateFavoriteColors(starter);
26 |
27 | // Get the faves
28 | // we should not find Vue green
29 | const { values: favesWithoutVueGreen } = getFavoriteColors();
30 | assert.ok(!favesWithoutVueGreen.find(item => item.name === vueGreenName));
31 |
32 | // Now write the recommended favorites
33 | await executeCommand(Commands.addRecommendedFavorites);
34 |
35 | // Get the faves
36 | const { values: faves } = getFavoriteColors();
37 |
38 | // we should have the 1 that was removed
39 | assert.ok(faves.find(item => item.name === vueGreenName));
40 | });
41 |
42 | test('any added ones are still there', async () => {
43 | // Start with starterSetOfFavorites
44 | await updateFavoriteColors(starterSetOfFavorites);
45 |
46 | // Add Night Blue #103362 to faves.
47 | const nightBlue = '#103362';
48 | const nightBlueName = 'Night Blue';
49 |
50 | // input the hex #103362
51 | const qiColorStub = await stubInputBox(nightBlue);
52 | await executeCommand(Commands.enterColor);
53 | qiColorStub.restore();
54 |
55 | // enter the name "Night Blue"
56 | const qiNameStub = await stubInputBox(nightBlueName);
57 | await executeCommand(Commands.saveColorToFavorites);
58 | qiNameStub.restore();
59 |
60 | // Now write the recommended favorites
61 | await executeCommand(Commands.addRecommendedFavorites);
62 |
63 | // Get the faves
64 | const { values: favoriteColorsAfter } = getFavoriteColors();
65 |
66 | // re-added and the one new one, as well/
67 | assert.ok(favoriteColorsAfter.find(item => item.name === nightBlueName));
68 | });
69 | });
70 |
71 | test('general test', async () => {
72 | // started with:
73 | // starterSetOfFavorites;
74 |
75 | const { values: favoriteColorsBefore } = getFavoriteColors();
76 |
77 | const vueGreen = favoriteColorsBefore.find(item => item.name === 'Vue Green') || {
78 | name: '',
79 | value: '',
80 | };
81 |
82 | const azureBlue = favoriteColorsBefore.find(item => item.name === 'Azure Blue') || {
83 | name: '',
84 | value: '',
85 | };
86 |
87 | const newRecs = {
88 | yodaGreen: {
89 | name: 'Yoda Green', // new key
90 | value: 'green', // new value
91 | },
92 | azureBlue: {
93 | name: 'Azure Blue', // same key
94 | value: '#007fff', // same value
95 | },
96 | vueGreen: {
97 | name: 'Vue Green', // same key
98 | value: 'lightgreen', // new value
99 | },
100 | };
101 |
102 | const testRecommended = [newRecs.vueGreen, newRecs.azureBlue, newRecs.yodaGreen];
103 |
104 | // Write 3 to favorites
105 | await writeRecommendedFavoriteColors(testRecommended);
106 | const { values: favoriteColors2 } = getFavoriteColors();
107 |
108 | // new unioned set should be one larger than before
109 | assert.ok(favoriteColors2.length === favoriteColorsBefore.length + 1);
110 |
111 | // 2 Should have same old value for existing favorite azure
112 | assert.ok(
113 | favoriteColors2.some(
114 | f =>
115 | f.name === azureBlue.name &&
116 | f.value === azureBlue.value &&
117 | f.value === newRecs.azureBlue.value,
118 | ),
119 | );
120 | // 2 Should have different value for existing favorite Vue Green
121 | console.log(vueGreen.name);
122 | console.log(vueGreen.value);
123 | console.log(newRecs.vueGreen.value);
124 | assert.ok(
125 | favoriteColors2.some(
126 | f =>
127 | f.name === vueGreen.name &&
128 | f.value !== vueGreen.value &&
129 | f.value === newRecs.vueGreen.value,
130 | ),
131 | );
132 | // 2 Should have new key and value pair (yoda/green)
133 | assert.ok(
134 | favoriteColors2.some(
135 | f => f.name === newRecs.yodaGreen.name && f.value === newRecs.yodaGreen.value,
136 | ),
137 | );
138 | });
139 | });
140 |
--------------------------------------------------------------------------------
/src/test/suite/status-bar.test.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as assert from 'assert';
3 | import { IPeacockSettings, Commands, getExtension, peacockGreen } from '../../models';
4 | import { setupTestSuite, teardownTestSuite, setupTest } from './lib/setup-teardown-test-suite';
5 | import { getStatusBarItem } from '../../statusbar';
6 |
7 | suite.skip('StatusBar Tests', () => {
8 | const originalValues = {} as IPeacockSettings;
9 | let extension: vscode.Extension;
10 |
11 | suiteSetup(async () => await setupTestSuite(originalValues));
12 | suiteTeardown(async () => await teardownTestSuite(originalValues));
13 | setup(async () => await setupTest());
14 |
15 | suiteSetup(() => {
16 | extension = getExtension() as vscode.Extension;
17 | });
18 |
19 | test('status bar', async () => {
20 | await extension.activate();
21 |
22 | await vscode.commands.executeCommand(Commands.changeColorToPeacockGreen);
23 |
24 | // show the status bar
25 | // await vscode.workspace
26 | // .getConfiguration()
27 | // .update('peacock.showColorInStatusBar', true, vscode.ConfigurationTarget.Global);
28 |
29 | const s = getStatusBarItem();
30 |
31 | // status bar should exist
32 | assert.ok(!!s);
33 |
34 | // status bar text should not be undefined
35 |
36 | assert.ok(s.text !== undefined);
37 |
38 | // statusbar text should have text
39 | assert.ok(s.text.length);
40 |
41 | // statusbar text should include current color
42 | assert.ok(s.text.includes(peacockGreen));
43 | });
44 | });
45 |
--------------------------------------------------------------------------------
/src/test/suite/surprise-me-on-startup.test.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as assert from 'assert';
3 | import {
4 | Commands,
5 | IPeacockSettings,
6 | IPeacockAffectedElementSettings,
7 | IElementColors,
8 | ElementNames,
9 | } from '../../models';
10 | import { setupTestSuite, teardownTestSuite, setupTest } from './lib/setup-teardown-test-suite';
11 | import { executeCommand } from './lib/constants';
12 | import {
13 | getOriginalColorsForAllElements,
14 | updateAffectedElements,
15 | updateSurpriseMeOnStartup,
16 | } from '../../configuration';
17 | import { checkSurpriseMeOnStartupLogic } from '../../extension';
18 |
19 | suite('Surprise me on startup', () => {
20 | const originalValues = {} as IPeacockSettings;
21 |
22 | suiteSetup(async () => await setupTestSuite(originalValues));
23 | suiteTeardown(async () => await teardownTestSuite(originalValues));
24 | setup(async () => await setupTest());
25 |
26 | setup(async () => {
27 | await executeCommand(Commands.resetWorkspaceColors);
28 | await updateAffectedElements({
29 | statusBar: true,
30 | activityBar: true,
31 | titleBar: true,
32 | } as IPeacockAffectedElementSettings);
33 | });
34 |
35 | test('when not set has no effect if no customizations exist', async () => {
36 | await testColorsBeforeAndAfterInitialConfiguration(assert.equal);
37 | });
38 |
39 | suite('when set', () => {
40 | setup(async () => {
41 | await updateSurpriseMeOnStartup(true);
42 | });
43 |
44 | test('applies a random color if no color customizations exist', async () => {
45 | await testColorsBeforeAndAfterInitialConfiguration(assert.notEqual);
46 | });
47 |
48 | test('has no effect when color customizations exist', async () => {
49 | await vscode.commands.executeCommand(Commands.changeColorToPeacockGreen);
50 | await testColorsBeforeAndAfterInitialConfiguration(assert.equal);
51 | });
52 |
53 | teardown(async () => {
54 | await updateSurpriseMeOnStartup(false);
55 | });
56 | });
57 |
58 | async function testColorsBeforeAndAfterInitialConfiguration(assertEquality: EqualityAssertion) {
59 | const colors1: IElementColors = getOriginalColorsForAllElements();
60 | await checkSurpriseMeOnStartupLogic();
61 | const colors2: IElementColors = getOriginalColorsForAllElements();
62 | assertEquality(colors1[ElementNames.activityBar], colors2[ElementNames.activityBar]);
63 | assertEquality(colors1[ElementNames.statusBar], colors2[ElementNames.statusBar]);
64 | assertEquality(colors1[ElementNames.titleBar], colors2[ElementNames.titleBar]);
65 | }
66 |
67 | interface EqualityAssertion {
68 | (actual: any, expected: any, message?: string | Error | undefined): void;
69 | }
70 | });
71 |
--------------------------------------------------------------------------------
/testworkspace/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | // Place your settings in this file to overwrite default and user settings.
2 | {
3 | "peacock.cacheBust": "827478",
4 | "peacock.color": "#f9e64f",
5 | "workbench.colorCustomizations": {
6 | "activityBar.activeBackground": "#fbed80",
7 | "activityBar.activeBorder": "#06b9a5",
8 | "activityBar.background": "#fbed80",
9 | "activityBar.foreground": "#15202b",
10 | "activityBar.inactiveForeground": "#15202b99",
11 | "activityBarBadge.background": "#06b9a5",
12 | "activityBarBadge.foreground": "#15202b",
13 | "sash.hoverBorder": "#fbed80",
14 | "statusBar.background": "#f9e64f",
15 | "statusBar.foreground": "#15202b",
16 | "statusBarItem.hoverBackground": "#f7df1e",
17 | "statusBarItem.remoteBackground": "#f9e64f",
18 | "statusBarItem.remoteForeground": "#15202b",
19 | "titleBar.activeBackground": "#f9e64f",
20 | "titleBar.activeForeground": "#15202b",
21 | "titleBar.inactiveBackground": "#f9e64f99",
22 | "titleBar.inactiveForeground": "#15202b99"
23 | },
24 | "peacock.remoteColor": ""
25 | }
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "es6",
5 | "outDir": "out",
6 | "lib": [
7 | "es6"
8 | ],
9 | "sourceMap": true,
10 | "rootDir": "src",
11 | "strict": true /* enable all strict type-checking options */
12 | /* Additional Checks */
13 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
14 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
15 | // "noUnusedParameters": true, /* Report errors on unused parameters. */
16 | },
17 | "exclude": [
18 | "node_modules",
19 | ".vscode-test"
20 | ]
21 | }
22 |
--------------------------------------------------------------------------------
/vsc-extension-quickstart.md:
--------------------------------------------------------------------------------
1 | # Welcome to your VS Code Extension
2 |
3 | ## What's in the folder
4 |
5 | - This folder contains all of the files necessary for your extension.
6 | - `package.json` - this is the manifest file in which you declare your extension and command.
7 | - The sample plugin registers a command and defines its title and command name. With this information VS Code can show the command in the command palette. It doesn’t yet need to load the plugin.
8 | - `src/extension.ts` - this is the main file where you will provide the implementation of your command.
9 | - The file exports one function, `activate`, which is called the very first time your extension is activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`.
10 | - We pass the function containing the implementation of the command as the second parameter to `registerCommand`.
11 |
12 | ## Get up and running straight away
13 |
14 | - Press `F5` to open a new window with your extension loaded.
15 | - Run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Hello World`.
16 | - Set breakpoints in your code inside `src/extension.ts` to debug your extension.
17 | - Find output from your extension in the debug console.
18 |
19 | ## Make changes
20 |
21 | - You can relaunch the extension from the debug toolbar after changing code in `src/extension.ts`.
22 | - You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes.
23 |
24 | ## Explore the API
25 |
26 | - You can open the full set of our API when you open the file `node_modules/vscode/vscode.d.ts`.
27 |
28 | ## Run tests
29 |
30 | - Open the debug viewlet (`Ctrl+Shift+D` or `Cmd+Shift+D` on Mac) and from the launch configuration dropdown pick `Extension Tests`.
31 | - Press `F5` to run the tests in a new window with your extension loaded.
32 | - See the output of the test result in the debug console.
33 | - Make changes to `test/extension.test.ts` or create new test files inside the `test` folder.
34 | - By convention, the test runner will only consider files matching the name pattern `**.test.ts`.
35 | - You can create folders inside the `test` folder to structure your tests any way you want.
36 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | //@ts-check
2 |
3 | 'use strict';
4 |
5 | const path = require('path');
6 |
7 | /**@type {import('webpack').Configuration}*/
8 | const baseConfig = {
9 | entry: './src/extension.ts', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/
10 | devtool: 'source-map',
11 | externals: {
12 | vscode: 'commonjs vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/
13 | },
14 | resolve: {
15 | // support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader
16 | extensions: ['.ts', '.js']
17 | },
18 | module: {
19 | rules: [
20 | {
21 | test: /\.ts$/,
22 | exclude: /node_modules/,
23 | use: [
24 | {
25 | loader: 'ts-loader'
26 | }
27 | ]
28 | }
29 | ]
30 | }
31 | };
32 |
33 | const nodeConfig = {
34 | ... baseConfig,
35 | target: 'node',
36 | output: {
37 | // the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/
38 | path: path.resolve(__dirname, 'dist'),
39 | filename: 'extension-node.js',
40 | libraryTarget: 'commonjs2',
41 | devtoolModuleFilenameTemplate: '../[resource-path]'
42 | }
43 | };
44 |
45 | const webConfig = {
46 | ... baseConfig,
47 | target: 'webworker',
48 | output: {
49 | // the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/
50 | path: path.resolve(__dirname, 'dist'),
51 | filename: 'extension-web.js',
52 | libraryTarget: 'commonjs2',
53 | devtoolModuleFilenameTemplate: '../[resource-path]'
54 | }
55 | };
56 |
57 | module.exports = [nodeConfig, webConfig];
58 |
--------------------------------------------------------------------------------