提交 c4f15b68 编写于 作者: 李少辉-开发者's avatar 李少辉-开发者 🎧

Init csdn workflow

Signed-off-by: 李少辉-开发者's avatarlish <lish@csdn.net>
上级 c30d9a98
node_modules
package-lock.json
.vscode-test/
.vsix
.history
......@@ -7,3 +8,5 @@ src/webview/dist/*.hot-update.js*
out
/coverage/
/reports/
.less
*.vsix
......@@ -489,7 +489,7 @@
# v3.2.0 - 2020-08-03
- Publish GitLab Workflow extension to Open VSX Registry [#205](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/issues/205)
- Publish CSDN Workflow extension to Open VSX Registry [#205](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/issues/205)
### Fixed
......@@ -720,7 +720,7 @@
### Added
- GitLab Workflow now supports multiple instances.
- CSDN Workflow now supports multiple instances.
- Implemented by [@csvn](https://gitlab.com/csvn) with [MR !5](https://gitlab.com/fatihacet/gitlab-vscode-extension/merge_requests/5) 👍
- ESLint and Prettier integration for dev environment.
- Added by [@alpcanaydin](https://gitlab.com/alpcanaydin) with [MR !6](https://gitlab.com/fatihacet/gitlab-vscode-extension/merge_requests/6) 👍
......
......@@ -17,9 +17,9 @@ _This notice should stay as the first item in the CONTRIBUTING.md file._
---
# Contributing to GitLab Workflow
# Contributing to CSDN Workflow
Thank you for your interest in contributing to GitLab Workflow! This guide details how to contribute
Thank you for your interest in contributing to CSDN Workflow! This guide details how to contribute
to this extension in a way that is easy for everyone. These are mostly guidelines, not rules.
Use your best judgement, and feel free to propose changes to this document in a merge request.
......@@ -48,14 +48,14 @@ as available [here](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/issu
For general information how to develop and debug VS Code Extensions, please see the [official documentation](https://code.visualstudio.com/api).
The following instructions will help you run the GitLab Workflow Extension locally.
The following instructions will help you run the CSDN Workflow Extension locally.
Please review our [Coding guidelines](docs/developer/coding-guidelines.md) before writing new code.
#### Step - 1 : Installation Prerequisites
We're assuming that you already have [Visual Studio Code](https://code.visualstudio.com/) installed along
with [GitLab Workflow](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow) installed
with [CSDN Workflow](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow) installed
and configured, if not, do that first! If already done, proceed ahead.
* [Git](https://git-scm.com/)
......@@ -124,8 +124,8 @@ npm run lint
### Opening Merge Requests
Steps to opening a merge request to contribute code to GitLab Workflow is similar to any other open source project.
Steps to opening a merge request to contribute code to CSDN Workflow is similar to any other open source project.
You develop in a separate branch of your own fork and the merge request should have a related issue open in the project.
Any Merge Request you wish to open in order to contribute to GitLab Workflow, be sure you have followed through the steps from [Configuring Development Environment](#configuring-development-environment).
Any Merge Request you wish to open in order to contribute to CSDN Workflow, be sure you have followed through the steps from [Configuring Development Environment](#configuring-development-environment).
In this project, we don't [close issues automatically when the MR gets merged](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically). Instead, we close the issues when the MR change is [released](docs/developer/release-process.md). Please replace `Closes #<issueId>` in the MR description with `Relates to #<issueId>`.
此差异已折叠。
{
"name": "gitlab-workflow",
"version": "3.25.0",
"name": "csdn-workflow",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
......@@ -1229,6 +1229,12 @@
"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=",
"dev": true
},
"@types/marked": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@types/marked/-/marked-2.0.4.tgz",
"integrity": "sha512-L9VRSe0Id8xbPL99mUo/4aKgD7ZoRwFZqUQScNKHi2pFjF9ZYSMNShUHD6VlMT6J/prQq0T1mxuU25m3R7dFzg==",
"dev": true
},
"@types/minimist": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.1.tgz",
......@@ -2331,8 +2337,7 @@
"boolbase": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
"dev": true
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
},
"brace-expansion": {
"version": "1.1.11",
......@@ -2567,13 +2572,12 @@
"dev": true
},
"cheerio": {
"version": "1.0.0-rc.9",
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.9.tgz",
"integrity": "sha512-QF6XVdrLONO6DXRF5iaolY+odmhj2CLj+xzNod7INPWMi/x9X4SOylH0S/vaPpX+AUU6t04s34SQNh7DbkuCng==",
"dev": true,
"version": "1.0.0-rc.10",
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz",
"integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==",
"requires": {
"cheerio-select": "^1.4.0",
"dom-serializer": "^1.3.1",
"cheerio-select": "^1.5.0",
"dom-serializer": "^1.3.2",
"domhandler": "^4.2.0",
"htmlparser2": "^6.1.0",
"parse5": "^6.0.1",
......@@ -2582,24 +2586,22 @@
},
"dependencies": {
"tslib": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
"integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==",
"dev": true
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
}
}
},
"cheerio-select": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.4.0.tgz",
"integrity": "sha512-sobR3Yqz27L553Qa7cK6rtJlMDbiKPdNywtR95Sj/YgfpLfy0u6CGJuaBKe5YE/vTc23SCRKxWSdlon/w6I/Ew==",
"dev": true,
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.5.0.tgz",
"integrity": "sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg==",
"requires": {
"css-select": "^4.1.2",
"css-what": "^5.0.0",
"css-select": "^4.1.3",
"css-what": "^5.0.1",
"domelementtype": "^2.2.0",
"domhandler": "^4.2.0",
"domutils": "^2.6.0"
"domutils": "^2.7.0"
}
},
"chokidar": {
......@@ -3101,10 +3103,9 @@
"dev": true
},
"css-select": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.2.tgz",
"integrity": "sha512-nu5ye2Hg/4ISq4XqdLY2bEatAcLIdt3OYGFc9Tm9n7VSlFBcfRv0gBNksHRgSdUDQGtN3XrZ94ztW+NfzkFSUw==",
"dev": true,
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz",
"integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==",
"requires": {
"boolbase": "^1.0.0",
"css-what": "^5.0.0",
......@@ -3116,8 +3117,7 @@
"css-what": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/css-what/-/css-what-5.0.1.tgz",
"integrity": "sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==",
"dev": true
"integrity": "sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg=="
},
"cssom": {
"version": "0.4.4",
......@@ -3358,21 +3358,19 @@
}
},
"dom-serializer": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.1.tgz",
"integrity": "sha512-Pv2ZluG5ife96udGgEDovOOOA5UELkltfJpnIExPrAk1LTvecolUGn6lIaoLh86d83GiB86CjzciMd9BuRB71Q==",
"dev": true,
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz",
"integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==",
"requires": {
"domelementtype": "^2.0.1",
"domhandler": "^4.0.0",
"domhandler": "^4.2.0",
"entities": "^2.0.0"
}
},
"domelementtype": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz",
"integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==",
"dev": true
"integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A=="
},
"domexception": {
"version": "2.0.1",
......@@ -3395,16 +3393,14 @@
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.0.tgz",
"integrity": "sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA==",
"dev": true,
"requires": {
"domelementtype": "^2.2.0"
}
},
"domutils": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.6.0.tgz",
"integrity": "sha512-y0BezHuy4MDYxh6OvolXYsH+1EMGmFbwv5FKW7ovwMG6zTPWqNPq3WF9ayZssFq+UlKdffGLbOEaghNdaOm1WA==",
"dev": true,
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.7.0.tgz",
"integrity": "sha512-8eaHa17IwJUPAiB+SoTYBo5mCdeMgdcAoXJ59m6DT1vw+5iLS3gNoqYaRowaBKtGVrOF1Jz4yDTgYKLK2kvfJg==",
"requires": {
"dom-serializer": "^1.0.1",
"domelementtype": "^2.2.0",
......@@ -3485,8 +3481,7 @@
"entities": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
"dev": true
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="
},
"error-ex": {
"version": "1.3.2",
......@@ -5289,6 +5284,11 @@
"integrity": "sha512-xAxZkM1dRyGV2Ou5bzMxBPNLoRCjcX+ya7KSWybQD2KwLphxsapUVK6x/02o7f4VU6GPSXch9vNY2+gkU8tYWQ==",
"dev": true
},
"highlight.js": {
"version": "11.2.0",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.2.0.tgz",
"integrity": "sha512-JOySjtOEcyG8s4MLR2MNbLUyaXqUunmSnL2kdV/KuGJOmHZuAR5xC54Ko7goAXBWNhf09Vy3B+U7vR62UZ/0iw=="
},
"hosted-git-info": {
"version": "3.0.8",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.8.tgz",
......@@ -5334,7 +5334,6 @@
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz",
"integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==",
"dev": true,
"requires": {
"domelementtype": "^2.0.1",
"domhandler": "^4.0.0",
......@@ -6577,7 +6576,8 @@
},
"hosted-git-info": {
"version": "2.8.8",
"resolved": "",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
"integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==",
"dev": true
},
"normalize-package-data": {
......@@ -7485,6 +7485,11 @@
}
}
},
"marked": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/marked/-/marked-2.1.3.tgz",
"integrity": "sha512-/Q+7MGzaETqifOMWYEA7HVMaZb4XbcRfaOzcSsHZEith83KGlvaSG33u0SKu89Mj5h+T8V2hM+8O45Qc5XTgwA=="
},
"md5": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
......@@ -7531,7 +7536,8 @@
"dependencies": {
"hosted-git-info": {
"version": "2.8.8",
"resolved": "",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
"integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==",
"dev": true
},
"read-pkg": {
......@@ -8284,7 +8290,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.0.tgz",
"integrity": "sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q==",
"dev": true,
"requires": {
"boolbase": "^1.0.0"
}
......@@ -8800,14 +8805,12 @@
"parse5": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
"integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==",
"dev": true
"integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw=="
},
"parse5-htmlparser2-tree-adapter": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz",
"integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==",
"dev": true,
"requires": {
"parse5": "^6.0.1"
}
......@@ -10999,6 +11002,11 @@
}
}
},
"timeago.js": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/timeago.js/-/timeago.js-4.0.2.tgz",
"integrity": "sha512-a7wPxPdVlQL7lqvitHGGRsofhdwtkoSXPGATFuSOA2i1ZNQEPLrGnj68vOp2sOJTCFAQVXPeNMX/GctBaO9L2w=="
},
"tmp": {
"version": "0.0.29",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.29.tgz",
......
此差异已折叠。
<?xml version="1.0" encoding="utf-8"?>
<svg viewBox="5.089 0.358 500 500" xmlns="http://www.w3.org/2000/svg">
<path class="cls-1" d="M 429.4 366.69 C 424.876 362.417 418.875 360.063 412.654 360.114 C 406.642 360.158 400.938 362.774 396.987 367.302 C 361.553 407.839 299.956 412.223 274.8 412.223 C 228.619 412.223 193.257 400.508 169.718 377.435 C 147.367 355.514 135.652 323.206 134.899 281.447 C 133.316 184.632 188.013 84.476 282.849 84.476 C 328.168 84.476 363.313 116.606 376.287 130.44 C 380.742 135.199 386.945 137.937 393.466 138.023 C 399.839 138.206 405.95 135.45 410.032 130.548 L 413.625 126.199 C 421.197 117.228 424.689 105.506 423.256 93.856 C 421.802 81.655 415.67 70.498 406.15 62.735 C 372.77 35.011 330.657 19.999 287.27 20.365 C 228.873 20.365 171.23 47.245 129.148 94.072 C 84.764 143.342 61.117 210.328 62.448 282.706 C 63.525 340.818 82.572 389.654 117.611 424.047 C 155.201 460.99 210.329 480.358 277.064 480.358 C 355.262 480.358 403.743 457.215 430.659 437.811 C 441.044 430.24 447.357 418.308 447.766 405.467 C 448.136 392.059 442.73 379.141 432.924 369.996 Z" style=""/>
<path class="cls-1" d="M 414.119 356.49 C 409.991 352.595 404.516 350.444 398.839 350.49 C 393.355 350.533 388.152 352.919 384.546 357.047 C 352.217 394.03 296.022 398.03 273.071 398.03 C 230.941 398.03 198.68 387.342 177.205 366.293 C 156.811 346.293 146.123 316.818 145.435 278.721 C 143.991 190.394 193.892 99.019 280.416 99.019 C 321.76 99.019 353.825 128.33 365.66 140.953 C 369.726 145.293 375.385 147.792 381.333 147.87 C 387.149 148.041 392.722 145.526 396.446 141.051 L 399.726 137.084 C 406.634 128.9 409.821 118.209 408.511 107.576 C 407.184 96.448 401.59 86.268 392.906 79.183 C 362.454 53.892 324.032 40.197 284.448 40.528 C 231.17 40.528 178.582 65.052 140.188 107.773 C 99.697 152.723 78.124 213.837 79.338 279.868 C 80.321 332.884 97.697 377.44 129.665 408.817 C 163.959 442.521 214.253 460.193 275.137 460.193 C 346.481 460.193 390.708 439.079 415.266 421.374 C 424.742 414.472 430.499 403.584 430.872 391.866 C 431.213 379.637 426.278 367.85 417.332 359.506 Z" style="fill: rgb(218, 51, 51); fill-opacity: 0; fill-rule: evenodd; stroke: rgb(255, 255, 255); stroke-width: 5px; visibility: hidden;"/>
</svg>
\ No newline at end of file
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 107.22 128.02">
<path class="cls-1" d="M112.39,96.37a6.71,6.71,0,0,0-4.66-1.83,5.85,5.85,0,0,0-4.36,2c-9.86,11.28-27,12.5-34,12.5-12.85,0-22.69-3.26-29.24-9.68-6.22-6.1-9.48-15.09-9.69-26.71C30,45.71,45.22,17.84,71.61,17.84c12.61,0,22.39,8.94,26,12.79a6.67,6.67,0,0,0,4.78,2.11A5.78,5.78,0,0,0,107,30.66l1-1.21a11.73,11.73,0,0,0,2.68-9,13.19,13.19,0,0,0-4.76-8.66A51.1,51.1,0,0,0,72.84,0c-16.25,0-32.29,7.48-44,20.51C16.49,34.22,9.91,52.86,10.28,73c.3,16.17,5.6,29.76,15.35,39.33C36.09,122.61,51.43,128,70,128c21.76,0,35.25-6.44,42.74-11.84a11.59,11.59,0,0,0,4.76-9,13,13,0,0,0-4.13-9.87Z" transform="translate(-10.26 -0.02)"/>
</svg>
\ No newline at end of file
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="tanuki-logo" viewBox="0 0 586 559">
<path d="m 582.78692,311.92227 -30.5816,-93.9636 a 13.2784,13.2784 0 0 0 -0.7396,-2.5284 L 490.11332,26.574273 A 24.3896,24.3896 0 0 0 466.82452,9.9418725 23.9768,23.9768 0 0 0 443.81092,26.711873 l -58.48,179.963597 H 200.75772 L 142.19172,26.711873 A 23.9768,23.9768 0 0 0 119.28132,9.9418725 h -0.1376 A 24.4584,24.4584 0 0 0 95.923723,26.729073 l -61.404,189.079597 c 0,0.172 -0.1376,0.3096 -0.1892,0.4816 l -31.1319998,95.6492 a 34.8988,34.8988 0 0 0 12.6763998,39.0612 l 268.973597,195.4436 a 13.76,13.76 0 0 0 16.254,-0.086 l 269.0252,-195.3576 a 34.8816,34.8816 0 0 0 12.6592,-39.0784 m -402.05,-77.6236 74.9748,230.7552 -179.980797,-230.7552 m 254.645997,230.8068 71.896,-221.2264 3.096,-9.5804 h 105.092 l -162.8324,208.6016 m 119.4368,-398.472397 52.6836,162.247597 h -105.4532 m -37.8916,27.52 -52.2364,160.7512 -31.1664,95.7352 -83.2824,-256.4864 M 119.02332,44.427873 171.81012,206.67547 H 66.425723 m -34.3656,122.0684 a 7.4132,7.4132 0 0 1 -2.6832,-8.3076 l 23.1168,-71.036 169.540397,217.3564 m 331.9256,-138.0128 -189.9912,137.9612 0.6364,-0.8256 168.904,-216.4792 23.1168,71.0016 a 7.4132,7.4132 0 0 1 -2.666,8.3248"/>
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 107.22 128.02">
<defs><style>.cls-1{fill:#ea5504;}</style></defs><path class="cls-1" d="M112.39,96.37a6.71,6.71,0,0,0-4.66-1.83,5.85,5.85,0,0,0-4.36,2c-9.86,11.28-27,12.5-34,12.5-12.85,0-22.69-3.26-29.24-9.68-6.22-6.1-9.48-15.09-9.69-26.71C30,45.71,45.22,17.84,71.61,17.84c12.61,0,22.39,8.94,26,12.79a6.67,6.67,0,0,0,4.78,2.11A5.78,5.78,0,0,0,107,30.66l1-1.21a11.73,11.73,0,0,0,2.68-9,13.19,13.19,0,0,0-4.76-8.66A51.1,51.1,0,0,0,72.84,0c-16.25,0-32.29,7.48-44,20.51C16.49,34.22,9.91,52.86,10.28,73c.3,16.17,5.6,29.76,15.35,39.33C36.09,122.61,51.43,128,70,128c21.76,0,35.25-6.44,42.74-11.84a11.59,11.59,0,0,0,4.76-9,13,13,0,0,0-4.13-9.87Z" transform="translate(-10.26 -0.02)"/>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<svg viewBox="5.089 0.358 500 500" xmlns="http://www.w3.org/2000/svg">
<path class="cls-1" d="M 429.4 366.69 C 424.875 362.417 418.874 360.064 412.653 360.114 C 406.642 360.158 400.938 362.774 396.986 367.303 C 361.552 407.839 299.955 412.224 274.799 412.224 C 228.618 412.224 193.256 400.509 169.717 377.435 C 147.366 355.514 135.651 323.207 134.898 281.448 C 133.315 184.632 188.012 84.476 282.848 84.476 C 328.167 84.476 363.312 116.606 376.286 130.44 C 380.742 135.199 386.945 137.937 393.466 138.023 C 399.839 138.206 405.949 135.45 410.031 130.549 L 413.625 126.199 C 421.196 117.229 424.688 105.506 423.255 93.856 C 421.802 81.655 415.669 70.498 406.149 62.735 C 372.769 35.011 330.656 19.999 287.269 20.365 C 228.872 20.365 171.229 47.245 129.147 94.072 C 84.763 143.342 61.116 210.329 62.447 282.707 C 63.524 340.818 82.571 389.654 117.61 424.048 C 155.2 460.991 210.328 480.358 277.064 480.358 C 355.262 480.358 403.743 457.215 430.659 437.811 C 441.044 430.24 447.357 418.309 447.766 405.468 C 448.135 392.059 442.729 379.141 432.924 369.996 Z" style="fill-rule: nonzero; stroke: rgb(255, 86, 55); stroke-linecap: round; paint-order: fill; fill: rgba(187, 218, 85, 0); stroke-width: 30px;"/>
<path class="cls-1" d="M 429.401 366.69 C 424.876 362.421 418.875 360.063 412.652 360.113 C 406.642 360.16 400.938 362.775 396.987 367.301 C 361.551 407.837 299.956 412.222 274.799 412.222 C 228.62 412.222 193.258 400.506 169.721 377.435 C 147.366 355.513 135.652 323.205 134.898 281.447 C 133.315 184.633 188.011 84.477 282.849 84.477 C 328.167 84.477 363.313 116.604 376.285 130.44 C 380.742 135.197 386.945 137.936 393.464 138.021 C 399.84 138.21 405.947 135.453 410.029 130.547 L 413.625 126.2 C 421.196 117.228 424.69 105.511 423.253 93.855 C 421.799 81.659 415.668 70.5 406.15 62.734 C 372.771 35.014 330.657 20.003 287.269 20.364 C 228.871 20.364 171.23 47.245 129.146 94.072 C 84.764 143.342 61.117 210.328 62.449 282.704 C 63.525 340.816 82.572 389.653 117.612 424.045 C 155.202 460.988 210.328 480.358 277.063 480.358 C 355.263 480.358 403.74 457.215 430.658 437.81 C 441.045 430.244 447.355 418.309 447.764 405.465 C 448.138 392.061 442.728 379.142 432.923 369.995 Z" style="fill: rgb(218, 51, 51); fill-opacity: 0; fill-rule: evenodd; stroke: rgb(255, 255, 255); stroke-width: 5px; visibility: hidden;"/>
</svg>
\ No newline at end of file
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 107.22 128.02">
<defs>
<style>
.cls-1{stroke: #ffffff;stroke-width:5;fill:#da3333;fill-opacity:0.0;fill-rule: evenodd;}
</style>
</defs>
<path class="cls-1" d="M112.39,96.37a6.71,6.71,0,0,0-4.66-1.83,5.85,5.85,0,0,0-4.36,2c-9.86,11.28-27,12.5-34,12.5-12.85,0-22.69-3.26-29.24-9.68-6.22-6.1-9.48-15.09-9.69-26.71C30,45.71,45.22,17.84,71.61,17.84c12.61,0,22.39,8.94,26,12.79a6.67,6.67,0,0,0,4.78,2.11A5.78,5.78,0,0,0,107,30.66l1-1.21a11.73,11.73,0,0,0,2.68-9,13.19,13.19,0,0,0-4.76-8.66A51.1,51.1,0,0,0,72.84,0c-16.25,0-32.29,7.48-44,20.51C16.49,34.22,9.91,52.86,10.28,73c.3,16.17,5.6,29.76,15.35,39.33C36.09,122.61,51.43,128,70,128c21.76,0,35.25-6.44,42.74-11.84a11.59,11.59,0,0,0,4.76-9,13,13,0,0,0-4.13-9.87Z" transform="translate(-10.26 -0.02)"/>
</svg>
\ No newline at end of file
pre code.hljs {
display: block;
overflow-x: auto;
padding: 0;
margin: 0;
}
code.hljs {
padding: 0;
}
.hljs {
color: #abb2bf;
background: transparent;
}
.hljs-comment,
.hljs-quote {
color: #5c6370;
font-style: italic;
}
.hljs-doctag,
.hljs-formula,
.hljs-keyword {
color: #c678dd;
}
.hljs-deletion,
.hljs-name,
.hljs-section,
.hljs-selector-tag,
.hljs-subst {
color: #e06c75;
}
.hljs-literal {
color: #56b6c2;
}
.hljs-addition,
.hljs-attribute,
.hljs-meta .hljs-string,
.hljs-regexp,
.hljs-string {
color: #98c379;
}
.hljs-attr,
.hljs-number,
.hljs-selector-attr,
.hljs-selector-class,
.hljs-selector-pseudo,
.hljs-template-variable,
.hljs-type,
.hljs-variable {
color: #d19a66;
}
.hljs-bullet,
.hljs-link,
.hljs-meta,
.hljs-selector-id,
.hljs-symbol,
.hljs-title {
color: #61aeee;
}
.hljs-built_in,
.hljs-class .hljs-title,
.hljs-title.class_ {
color: #e6c07b;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: 700;
}
.hljs-link {
text-decoration: underline;
}
pre code.hljs {
display: block;
overflow-x: auto;
padding: 1em;
}
code.hljs {
padding: 3px 5px;
} /*!
Theme: GitHub
Description: Light theme as seen on github.com
Author: github.com
Maintainer: @Hirse
Updated: 2021-05-15
Outdated base version: https://github.com/primer/github-syntax-light
Current colors taken from GitHub's CSS
*/
.hljs {
color: #24292e;
background: #fff;
}
.hljs-doctag,
.hljs-keyword,
.hljs-meta .hljs-keyword,
.hljs-template-tag,
.hljs-template-variable,
.hljs-type,
.hljs-variable.language_ {
color: #d73a49;
}
.hljs-title,
.hljs-title.class_,
.hljs-title.class_.inherited__,
.hljs-title.function_ {
color: #6f42c1;
}
.hljs-attr,
.hljs-attribute,
.hljs-literal,
.hljs-meta,
.hljs-number,
.hljs-operator,
.hljs-selector-attr,
.hljs-selector-class,
.hljs-selector-id,
.hljs-variable {
color: #005cc5;
}
.hljs-meta .hljs-string,
.hljs-regexp,
.hljs-string {
color: #032f62;
}
.hljs-built_in,
.hljs-symbol {
color: #e36209;
}
.hljs-code,
.hljs-comment,
.hljs-formula {
color: #6a737d;
}
.hljs-name,
.hljs-quote,
.hljs-selector-pseudo,
.hljs-selector-tag {
color: #22863a;
}
.hljs-subst {
color: #24292e;
}
.hljs-section {
color: #005cc5;
font-weight: 700;
}
.hljs-bullet {
color: #735c0f;
}
.hljs-emphasis {
color: #24292e;
font-style: italic;
}
.hljs-strong {
color: #24292e;
font-weight: 700;
}
.hljs-addition {
color: #22863a;
background-color: #f0fff4;
}
.hljs-deletion {
color: #b31d28;
background-color: #ffeef0;
}
.md_preview address,
.md_preview cite,
.md_preview dfn,
.md_preview em,
.md_preview i,
.md_preview span[lang],
.md_preview var {
font-style: italic;
}
.md_preview {
font-family: -apple-system, SF UI Text, Arial, PingFang SC, Hiragino Sans GB, Microsoft YaHei, WenQuanYi Micro Hei, sans-serif, SimHei, SimSun;
padding: 0 14px;
box-sizing: border-box;
word-break: break-all;
}
.md_preview code {
padding: 10px 14px !important;
box-sizing: border-box;
border: 1px solid #3794ff;
}
.md_preview img {
max-width: 100%;
height: auto;
}
.md_preview img.right {
border: 1px solid #ccc;
float: right;
margin-left: 15px;
padding: 5px;
}
.md_preview img.left {
border: 1px solid #ccc;
float: left;
margin-right: 15px;
padding: 5px;
}
.md_preview img.mathcode {
margin: 0 8px;
}
.md_preview .marker {
background-color: #ff0;
}
.md_preview figure {
text-align: center;
margin: 0 24px;
display: inline-block;
}
.md_preview figure > figcaption {
text-align: center;
margin: 8px;
color: #999;
font-size: 14px;
display: block;
}
.md_preview a {
color: #4ea1db;
text-decoration: none;
}
.md_preview a > img {
padding: 1px;
margin: 1px;
border: none;
outline: #0782c1 solid 1px;
}
.md_preview a:visited {
color: #6795b5;
}
.md_preview .code-featured {
border: 5px solid red;
}
.md_preview .math-featured {
padding: 20px;
box-shadow: 0 0 2px #c80000;
background-color: rgba(255, 0, 0, 0.05);
margin: 10px;
}
.md_preview .image-clean {
border: 0;
background: 0 0;
padding: 0;
}
.md_preview .image-clean > figcaption {
font-size: 0.9em;
text-align: right;
}
.md_preview .image-grayscale {
background-color: #fff;
color: #666;
}
.md_preview .embed-240p {
max-width: 426px;
max-height: 240px;
margin: 0 auto;
}
.md_preview .embed-360p {
max-width: 640px;
max-height: 360px;
margin: 0 auto;
}
.md_preview .embed-480p {
max-width: 854px;
max-height: 480px;
margin: 0 auto;
}
.md_preview .embed-720p {
max-width: 1280px;
max-height: 720px;
margin: 0 auto;
}
.md_preview .embed-1080p {
max-width: 1920px;
max-height: 1080px;
margin: 0 auto;
}
.md_preview p {
font-size: 16px;
color: var(--md-editor-text-color-active);
font-weight: 400;
line-height: 26px !important;
margin: 0 0 16px;
overflow-x: auto;
overflow-y: hidden;
}
.md_preview * {
box-sizing: border-box;
}
.md_preview ul ol {
margin: 0 0 24px 32px;
}
.md_preview ul li {
list-style-type: disc;
margin: 8px 0 0 32px;
}
.md_preview ol li {
list-style-type: decimal;
margin-left: 40px;
margin-top: 8px;
}
.md_preview h1 {
font-size: 28px;
line-height: 36px;
}
.md_preview h2 {
font-size: 24px;
line-height: 32px;
}
.md_preview h3 {
font-size: 22px;
line-height: 30px;
}
.md_preview h4 {
font-size: 20px;
line-height: 28px;
}
.md_preview h5 {
font-size: 18px;
line-height: 26px;
}
.md_preview h6 {
font-size: 16px;
line-height: 24px;
}
.md_preview blockquote {
display: block;
padding: 16px 16px 0;
margin: 0 0 24px;
border-left: 8px solid #dddfe4;
background: #eef0f4;
overflow: auto;
overflow-scrolling: touch;
word-wrap: normal;
word-break: normal;
}
.md_preview blockquote p {
font-size: 16px;
line-height: 26px;
font-weight: 400;
margin-bottom: 16px;
color: #4f4f4f;
}
.md_preview hr {
margin: 24px 0;
border: none;
border-bottom: solid #ccc 1px;
}
.md_preview table {
border-collapse: collapse;
display: table;
width: 100%;
text-align: left;
margin-bottom: 24px;
margin-left: auto;
margin-right: auto;
}
.md_preview table tr {
border: 0;
border-top: 1px solid #ddd;
background-color: #fff;
}
.md_preview table tr:nth-child(2n) {
background-color: #f7f7f7;
}
.md_preview table tr th {
font-weight: 700;
background-color: #eff3f5;
}
.md_preview table tr th p {
font-weight: 700;
}
.md_preview tbody {
border: 0;
}
.md_preview dl {
margin: 24px;
}
.md_preview dl dt {
margin: 8px;
font-weight: 700;
}
.md_preview dl dt dd {
margin: 8px;
}
.md_preview dl dd {
margin: 0 0 8px 40px;
}
.md_preview .initialism {
font-size: 90%;
text-transform: uppercase;
}
.md_preview pre {
white-space: pre-wrap;
word-wrap: break-word;
margin: 0 0 24px;
overflow-x: auto;
}
.md_preview pre code {
display: block;
line-height: 22px;
overflow-x: auto;
white-space: pre;
word-wrap: normal;
border-radius: 4px;
padding: 8px;
tab-size: 4;
}
.md_preview pre code code.md_hljs {
padding: 0;
}
.md_preview code {
border-radius: 4px;
display: inline-block;
padding: 2px 6px;
font-family: -apple-system, SF UI Text, Arial, PingFang SC, Hiragino Sans GB, Microsoft YaHei, WenQuanYi Micro Hei, sans-serif, SimHei, SimSun;
}
.md_preview code ol {
margin: 0;
overflow: hidden;
}
.md_preview code ol li {
list-style-type: none;
margin-left: 0;
margin-top: 0;
height: 22px;
}
.md_preview code ol li div.hljs-ln-code {
margin-left: 8px;
}
.md_preview code ol li div.hljs-ln-numbers {
width: 24px;
border-right: 1px solid #c5c5c5;
}
.md_preview code ol li div.hljs-ln-numbers .hljs-ln-line {
word-wrap: normal;
}
.md_preview code ol.hundred li div.hljs-ln-numbers {
width: 30px;
}
.md_preview code ol.thousand li div.hljs-ln-numbers {
width: 36px;
}
.md_preview .hot-keyword:visited {
color: #3399ea;
}
.md_preview .footnote {
vertical-align: top;
position: relative;
top: -4px;
font-size: 12px;
}
.md_preview .MathJax_SVG_Display {
text-align: center;
margin: 24px 0;
font-size: 18px;
font-weight: 400;
color: #4f4f4f;
position: relative;
text-indent: 0;
max-width: none;
max-height: none;
min-width: 0;
min-height: 0;
width: 100%;
}
.md_preview .prettyprint .pre-numbering {
position: absolute;
width: 48px;
background-color: #eef0f4;
top: 0;
left: 0;
margin: 0;
padding: 8px 0;
list-style: none;
text-align: right;
}
.md_preview .pre-numbering li {
padding: 0 8px;
list-style: none;
margin: 0;
}
.md_preview kbd {
padding: 2px 8px;
border: 1px solid rgba(63, 63, 63, 0.25);
box-shadow: 0 1px 0 rgba(63, 63, 63, 0.25);
background-color: #fff;
color: #333;
border-radius: 4px;
display: inline-block;
margin: 0 2px;
white-space: nowrap;
}
.md_preview .dp-highlighter {
font-size: 12px;
text-align: left;
margin: 0 0 24px;
}
.md_preview .csdn-data-video {
width: 200px;
}
.md_preview .csdn-data-video img {
margin: 0;
display: block;
width: 200px;
height: 112px;
}
.md_preview .csdn-data-video p {
margin-top: 10px;
margin-bottom: 0;
font-size: 14px;
}
.md_preview pre[data-from='code-for-outside'] {
overflow: hidden;
}
.md_preview pre[data-from='code-for-outside'] code {
overflow-x: auto;
overflow-y: hidden;
}
.md_preview pre[data-from='code-for-outside'] code * {
overflow: visible;
overflow-wrap: break-word;
}
.md_preview pre[data-from='code-for-outside'] p code {
padding: 0;
}
.cke_editable {
margin: 24px;
word-wrap: break-word;
}
.md_preview .image-grayscale img,
.md_preview img.image-grayscale {
filter: grayscale(100%);
}
p[align='center'] {
text-align: center;
}
.md_preview strong,
.md_preview strong span,
.md_preview strong em {
font-weight: 700;
}
.md_preview em strong {
font-style: italic;
}
.md_preview h1,
.md_preview h2,
.md_preview h3,
.md_preview h4,
.md_preview h5,
.md_preview h6 {
color: #4f4f4f;
margin: 8px 0 16px;
font-weight: 700;
}
.md_preview ol,
.md_preview ul {
margin: 0 0 24px;
padding: 0;
font-size: 16px;
}
.md_preview blockquote ol,
.md_preview blockquote ul {
margin-bottom: 16px;
padding: 0;
font-size: 16px;
line-height: 24px;
}
.md_preview blockquote ol li,
.md_preview blockquote ul li {
margin-bottom: 0;
}
.md_preview table tr td,
.md_preview table tr th {
border: 1px solid #ddd;
font-size: 14px;
color: #4f4f4f;
line-height: 22px;
padding: 8px;
text-align: left;
}
.md_preview table tr td p,
.md_preview table tr th p {
font-size: 14px;
color: #4f4f4f;
margin: 0;
padding: 0;
text-align: left;
line-height: 22px;
}
.md_preview table tr td code,
.md_preview table tr th code {
white-space: normal;
word-break: break-word;
}
.md_preview abbr[data-original-title],
.md_preview abbr[title] {
cursor: help;
border-bottom: 1px dotted #999;
}
.marker {
background-color: #ff0;
}
.md_preview pre {
overflow: hidden;
}
.md_preview pre code {
overflow-y: hidden;
}
.md_preview kbd,
.md_preview pre,
.md_preview samp {
font-family: Consolas, Inconsolata, Courier, monospace;
font-size: 14px;
line-height: 22px;
}
.md_preview code ol li div.hljs-ln-code,
.md_preview code ol li div.hljs-ln-numbers,
.md_preview pre code,
.md_preview pre code div,
.md_preview pre code span {
font-family: 'Source Code Pro', 'DejaVu Sans Mono', 'Ubuntu Mono', 'Anonymous Pro', 'Droid Sans Mono', Menlo, Monaco, Consolas, Inconsolata, Courier, monospace, 'PingFang SC', 'Microsoft YaHei', sans-serif;
}
.md_preview a:focus,
.md_preview a:hover {
color: #ca0c16;
}
.md_preview .flow-chart,
.md_preview .sequence-diagram {
text-align: center;
margin-bottom: 24px;
font-size: 14px !important;
}
.md_preview .flow-chart [fill='#000'],
.md_preview .flow-chart [fill='#000000'],
.md_preview .flow-chart [fill='black'],
.md_preview .sequence-diagram [fill='#000'],
.md_preview .sequence-diagram [fill='#000000'],
.md_preview .sequence-diagram [fill='black'] {
fill: #4f4f4f;
}
.md_preview .flow-chart [stroke='#000000'],
.md_preview .sequence-diagram [stroke='#000000'] {
stroke: #4f4f4f;
}
.md_preview pre code,
.md_preview pre code div,
.md_preview pre code span {
font-size: 14px;
}
.md_preview .prettyprint,
.md_preview pre.prettyprint {
margin: 0 0 24px;
padding: 8px 16px 4px 56px;
background-color: #f6f8fa;
border: none;
}
.md_preview code ol li div.hljs-ln-code,
.md_preview code ol li div.hljs-ln-numbers {
float: left;
height: 22px;
}
.md_preview pre code .hljs-comment {
color: green;
}
.md_preview address,
.md_preview cite,
.md_preview dfn,
.md_preview em,
.md_preview i,
.md_preview span[lang],
.md_preview var {
font-style: italic;
}
.md_preview {
font-family: -apple-system, SF UI Text, Arial, PingFang SC, Hiragino Sans GB, Microsoft YaHei,
WenQuanYi Micro Hei, sans-serif, SimHei, SimSun;
padding: 0 14px;
box-sizing: border-box;
word-break: break-all;
code {
padding: 10px 14px !important;
box-sizing: border-box;
border: 1px solid #3794ff;
}
img {
max-width: 100%;
height: auto;
&.right {
border: 1px solid #ccc;
float: right;
margin-left: 15px;
padding: 5px;
}
&.left {
border: 1px solid #ccc;
float: left;
margin-right: 15px;
padding: 5px;
}
&.mathcode {
margin: 0 8px;
}
}
.marker {
background-color: #ff0;
}
figure {
text-align: center;
margin: 0 24px;
display: inline-block;
& > figcaption {
text-align: center;
margin: 8px;
color: #999;
font-size: 14px;
display: block;
}
}
a {
color: #4ea1db;
text-decoration: none;
& > img {
padding: 1px;
margin: 1px;
border: none;
outline: #0782c1 solid 1px;
}
&:visited {
color: #6795b5;
}
}
.code-featured {
border: 5px solid red;
}
.math-featured {
padding: 20px;
box-shadow: 0 0 2px rgba(200, 0, 0, 1);
background-color: rgba(255, 0, 0, 0.05);
margin: 10px;
}
.image-clean {
border: 0;
background: 0 0;
padding: 0;
& > figcaption {
font-size: 0.9em;
text-align: right;
}
}
.image-grayscale {
background-color: #fff;
color: #666;
}
.embed-240p {
max-width: 426px;
max-height: 240px;
margin: 0 auto;
}
.embed-360p {
max-width: 640px;
max-height: 360px;
margin: 0 auto;
}
.embed-480p {
max-width: 854px;
max-height: 480px;
margin: 0 auto;
}
.embed-720p {
max-width: 1280px;
max-height: 720px;
margin: 0 auto;
}
.embed-1080p {
max-width: 1920px;
max-height: 1080px;
margin: 0 auto;
}
p {
font-size: 16px;
color: var(--md-editor-text-color-active);
font-weight: 400;
line-height: 26px !important;
margin: 0 0 16px;
overflow-x: auto;
overflow-y: hidden;
}
* {
box-sizing: border-box;
}
ul {
ol {
margin: 0 0 24px 32px;
}
li {
list-style-type: disc;
margin: 8px 0 0 32px;
}
}
ol {
li {
list-style-type: decimal;
margin-left: 40px;
margin-top: 8px;
}
}
h1 {
font-size: 28px;
line-height: 36px;
}
h2 {
font-size: 24px;
line-height: 32px;
}
h3 {
font-size: 22px;
line-height: 30px;
}
h4 {
font-size: 20px;
line-height: 28px;
}
h5 {
font-size: 18px;
line-height: 26px;
}
h6 {
font-size: 16px;
line-height: 24px;
}
blockquote {
display: block;
padding: 16px 16px 0;
margin: 0 0 24px;
border-left: 8px solid #dddfe4;
background: #eef0f4;
overflow: auto;
overflow-scrolling: touch;
word-wrap: normal;
word-break: normal;
p {
font-size: 16px;
line-height: 26px;
font-weight: 400;
margin-bottom: 16px;
color: #4f4f4f;
}
}
hr {
margin: 24px 0;
border: none;
border-bottom: solid #ccc 1px;
}
table {
border-collapse: collapse;
display: table;
width: 100%;
text-align: left;
margin-bottom: 24px;
margin-left: auto;
margin-right: auto;
tr {
border: 0;
border-top: 1px solid #ddd;
background-color: #fff;
&:nth-child(2n) {
background-color: #f7f7f7;
}
th {
font-weight: 700;
background-color: #eff3f5;
p {
font-weight: 700;
}
}
}
}
tbody {
border: 0;
}
dl {
margin: 24px;
dt {
margin: 8px;
font-weight: 700;
dd {
margin: 8px;
}
}
dd {
margin: 0 0 8px 40px;
}
}
.initialism {
font-size: 90%;
text-transform: uppercase;
}
pre {
white-space: pre-wrap;
word-wrap: break-word;
margin: 0 0 24px;
overflow-x: auto;
// padding: 8px;
code {
display: block;
line-height: 22px;
overflow-x: auto;
white-space: pre;
word-wrap: normal;
border-radius: 4px;
padding: 8px;
tab-size: 4;
code {
&.md_hljs {
padding: 0;
}
}
&:not(.md_hljs) {
// background-color: var(--md-editor-code-bg-color);
}
}
}
code {
border-radius: 4px;
display: inline-block;
// background-color: var(--md-editor-code-bg-color);
padding: 2px 6px;
font-family: -apple-system, SF UI Text, Arial, PingFang SC, Hiragino Sans GB, Microsoft YaHei,
WenQuanYi Micro Hei, sans-serif, SimHei, SimSun;
ol {
margin: 0;
overflow: hidden;
li {
list-style-type: none;
margin-left: 0;
margin-top: 0;
height: 22px;
div {
&.hljs-ln-code {
margin-left: 8px;
}
&.hljs-ln-numbers {
width: 24px;
border-right: 1px solid #c5c5c5;
.hljs-ln-line {
word-wrap: normal;
}
}
}
}
&.hundred {
li {
div {
&.hljs-ln-numbers {
width: 30px;
}
}
}
}
&.thousand {
li {
div {
&.hljs-ln-numbers {
width: 36px;
}
}
}
}
}
}
.hot-keyword {
&:visited {
color: #3399ea;
}
}
.footnote {
vertical-align: top;
position: relative;
top: -4px;
font-size: 12px;
}
.MathJax_SVG_Display {
text-align: center;
margin: 24px 0;
font-size: 18px;
font-weight: 400;
color: #4f4f4f;
position: relative;
text-indent: 0;
max-width: none;
max-height: none;
min-width: 0;
min-height: 0;
width: 100%;
}
.prettyprint {
.pre-numbering {
position: absolute;
width: 48px;
background-color: #eef0f4;
top: 0;
left: 0;
margin: 0;
padding: 8px 0;
list-style: none;
text-align: right;
}
}
.pre-numbering {
li {
padding: 0 8px;
list-style: none;
margin: 0;
}
}
kbd {
padding: 2px 8px;
border: 1px solid rgba(63, 63, 63, 0.25);
box-shadow: 0 1px 0 rgba(63, 63, 63, 0.25);
background-color: #fff;
color: #333;
border-radius: 4px;
display: inline-block;
margin: 0 2px;
white-space: nowrap;
}
.dp-highlighter {
font-size: 12px;
text-align: left;
margin: 0 0 24px;
}
.csdn-data-video {
width: 200px;
img {
margin: 0;
display: block;
width: 200px;
height: 112px;
}
p {
margin-top: 10px;
margin-bottom: 0;
font-size: 14px;
}
}
pre[data-from='code-for-outside'] {
overflow: hidden;
code {
overflow-x: auto;
overflow-y: hidden;
* {
overflow: visible;
overflow-wrap: break-word;
}
}
p {
code {
padding: 0;
}
}
}
}
.cke_editable {
margin: 24px;
word-wrap: break-word;
}
.md_preview .image-grayscale img,
.md_preview img.image-grayscale {
filter: grayscale(100%);
}
p[align='center'] {
text-align: center;
}
.md_preview strong,
.md_preview strong span,
.md_preview strong em {
font-weight: 700;
}
.md_preview em strong {
font-style: italic;
}
.md_preview h1,
.md_preview h2,
.md_preview h3,
.md_preview h4,
.md_preview h5,
.md_preview h6 {
color: #4f4f4f;
margin: 8px 0 16px;
font-weight: 700;
}
.md_preview ol,
.md_preview ul {
margin: 0 0 24px;
padding: 0;
font-size: 16px;
}
.md_preview blockquote ol,
.md_preview blockquote ul {
margin-bottom: 16px;
padding: 0;
font-size: 16px;
line-height: 24px;
}
.md_preview blockquote ol li,
.md_preview blockquote ul li {
margin-bottom: 0;
}
.md_preview table tr td,
.md_preview table tr th {
border: 1px solid #ddd;
font-size: 14px;
color: #4f4f4f;
line-height: 22px;
padding: 8px;
text-align: left;
}
.md_preview table tr td p,
.md_preview table tr th p {
font-size: 14px;
color: #4f4f4f;
margin: 0;
padding: 0;
text-align: left;
line-height: 22px;
}
.md_preview table tr td code,
.md_preview table tr th code {
white-space: normal;
word-break: break-word;
}
.md_preview abbr[data-original-title],
.md_preview abbr[title] {
cursor: help;
border-bottom: 1px dotted #999;
}
.marker {
background-color: #ff0;
}
.md_preview pre {
overflow: hidden;
code {
overflow-y: hidden;
}
}
.md_preview kbd,
.md_preview pre,
.md_preview samp {
font-family: Consolas, Inconsolata, Courier, monospace;
font-size: 14px;
line-height: 22px;
// color: #000;
}
.md_preview code ol li div.hljs-ln-code,
.md_preview code ol li div.hljs-ln-numbers,
.md_preview pre code,
.md_preview pre code div,
.md_preview pre code span {
font-family: 'Source Code Pro', 'DejaVu Sans Mono', 'Ubuntu Mono', 'Anonymous Pro',
'Droid Sans Mono', Menlo, Monaco, Consolas, Inconsolata, Courier, monospace, 'PingFang SC',
'Microsoft YaHei', sans-serif;
}
.md_preview a:focus,
.md_preview a:hover {
color: #ca0c16;
}
.md_preview .flow-chart,
.md_preview .sequence-diagram {
text-align: center;
margin-bottom: 24px;
font-size: 14px !important;
}
.md_preview .flow-chart [fill='#000'],
.md_preview .flow-chart [fill='#000000'],
.md_preview .flow-chart [fill='black'],
.md_preview .sequence-diagram [fill='#000'],
.md_preview .sequence-diagram [fill='#000000'],
.md_preview .sequence-diagram [fill='black'] {
fill: #4f4f4f;
}
.md_preview .flow-chart [stroke='#000000'],
.md_preview .sequence-diagram [stroke='#000000'] {
stroke: #4f4f4f;
}
.md_preview pre code,
.md_preview pre code div,
.md_preview pre code span {
font-size: 14px;
}
.md_preview .prettyprint,
.md_preview pre.prettyprint {
margin: 0 0 24px;
padding: 8px 16px 4px 56px;
background-color: #f6f8fa;
border: none;
}
.md_preview code ol li div.hljs-ln-code,
.md_preview code ol li div.hljs-ln-numbers {
float: left;
height: 22px;
}
.md_preview pre code .hljs-comment {
color: green;
}
.snippet_header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 14px 0;
box-sizing: border-box;
border-bottom: 1px solid #4c4c4c;
}
.snippet_header img {
width: 20px;
height: 20px;
border-radius: 50%;
}
.snippet_header .flex-1 {
flex: 1;
margin: 0 14px;
}
.snippet_header a {
margin: 0 6px;
outline: none;
}
.snippet_title {
font-size: 20px;
}
.snippet_desc {
color: #ccc;
}
.snippet_desc.md_preview {
padding: 0;
}
.snippet_item_container {
border: 1px solid #3794ff;
border-radius: 4px;
margin: 20px 0;
}
.snippet_item_container .snippet_item_header {
border-bottom: 1px solid #3794ff;
font-size: 16px;
padding: 6px 14px;
box-sizing: border-box;
}
.snippet_item_container .snippet_item_header .snippet_item_title {
display: inline-block;
font-weight: 600;
}
.snippet_item_container .snippet_item_header .snippet_item_size {
display: inline-block;
margin: 0 20px 0 10px;
font-size: 12px;
color: #ccc;
}
.snippet_item_container .snippet_item_header .snippet_item_copy {
font-size: 12px;
outline: none;
}
.snippet_item_container .snippet_item_body .snippet_content pre {
white-space: pre-wrap;
word-wrap: break-word;
overflow-x: auto;
margin: 0;
padding: 0;
}
.snippet_item_container .snippet_item_body .snippet_content pre code {
display: block;
line-height: 1.2;
overflow-x: auto;
white-space: pre;
word-wrap: normal;
tab-size: 2;
padding: 0 6px;
box-sizing: border-box;
margin: 0;
}
.snippet_item_container .snippet_item_body .snippet_content pre code ul {
list-style: decimal;
margin: 0 0 0 40px;
padding: 0;
}
.snippet_item_container .snippet_item_body .snippet_content pre code ul li {
list-style: decimal;
border-left: 1px solid #3794ff;
padding: 2px 5px;
margin: 0;
line-height: 14px;
width: 100%;
box-sizing: border-box;
}
.snippet_item_container .snippet_item_body .snippet_content pre code ul li:first-child {
padding-top: 6px;
}
.snippet_item_container .snippet_item_body .snippet_content pre code ul li:last-child {
padding-bottom: 6px;
}
.snippet_item_container .snippet_item_body .snippet_content pre code ul li::marker {
content: counter(list-item) ' ';
color: #808080;
}
@color-blue: #3794ff;
.snippet_header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 14px 0;
box-sizing: border-box;
border-bottom: 1px solid #4c4c4c;
img {
width: 20px;
height: 20px;
border-radius: 50%;
}
.flex-1 {
flex: 1;
margin: 0 14px;
}
a {
margin: 0 6px;
outline: none;
}
}
.snippet_title {
font-size: 20px;
}
.snippet_desc {
color: #ccc;
&.md_preview {
padding: 0;
}
}
.snippet_item_container {
border: 1px solid @color-blue;
border-radius: 4px;
margin: 20px 0;
.snippet_item_header {
border-bottom: 1px solid @color-blue;
font-size: 16px;
padding: 6px 14px;
box-sizing: border-box;
.snippet_item_title {
display: inline-block;
font-weight: 600;
}
.snippet_item_size {
display: inline-block;
margin: 0 20px 0 10px;
font-size: 12px;
color: #ccc;
}
.snippet_item_copy {
font-size: 12px;
outline: none;
}
}
.snippet_item_body {
.snippet_content {
pre {
// border-left: 1px solid @color-blue;
white-space: pre-wrap;
word-wrap: break-word;
overflow-x: auto;
margin: 0;
padding: 0;
code {
display: block;
line-height: 1.2;
overflow-x: auto;
white-space: pre;
word-wrap: normal;
tab-size: 2;
padding: 0 6px;
box-sizing: border-box;
margin: 0;
ul {
list-style: decimal;
margin: 0 0 0 40px;
padding: 0;
li {
list-style: decimal;
border-left: 1px solid @color-blue;
padding: 2px 5px;
margin: 0;
line-height: 14px;
width: 100%;
box-sizing: border-box;
&:first-child {
padding-top: 6px;
}
&:last-child {
padding-bottom: 6px;
}
&::marker {
content: counter(list-item) ' ';
color: #808080;
}
// &:nth-of-type(even) {
// background-color: rgba(255, 255, 255, 0.015);
// color: inherit;
// }
}
}
}
}
}
}
}
......@@ -6,7 +6,7 @@ export async function validate(): Promise<void> {
const editor = vscode.window.activeTextEditor;
if (!editor) {
await vscode.window.showInformationMessage('GitLab Workflow: No open file.');
await vscode.window.showInformationMessage('CSDN Workflow: No open file.');
return;
}
......@@ -18,7 +18,7 @@ export async function validate(): Promise<void> {
if (!response) {
await vscode.window.showInformationMessage(
'GitLab Workflow: Failed to validate CI configuration.',
'CSDN Workflow: Failed to validate CI configuration.',
);
return;
}
......@@ -26,16 +26,16 @@ export async function validate(): Promise<void> {
const { status, errors, error } = response;
if (status === 'valid') {
await vscode.window.showInformationMessage('GitLab Workflow: Your CI configuration is valid.');
await vscode.window.showInformationMessage('CSDN Workflow: Your CI configuration is valid.');
} else if (status === 'invalid') {
if (errors[0]) {
await vscode.window.showErrorMessage(errors[0]);
}
await vscode.window.showErrorMessage('GitLab Workflow: Invalid CI configuration.');
await vscode.window.showErrorMessage('CSDN Workflow: Invalid CI configuration.');
} else if (error) {
await vscode.window.showErrorMessage(
`GitLab Workflow: Failed to validate CI configuration. Reason: ${error}`,
`CSDN Workflow: Failed to validate CI configuration. Reason: ${error}`,
);
}
}
......@@ -3,45 +3,54 @@
These commands must be exactly the same as the contributed commands in package.json.
*/
export const USER_COMMANDS = {
SET_TOKEN: 'gl.setToken',
REMOVE_TOKEN: 'gl.removeToken',
SHOW_ISSUES_ASSIGNED_TO_ME: 'gl.showIssuesAssignedToMe',
SHOW_MERGE_REQUESTS_ASSIGNED_TO_ME: 'gl.showMergeRequestsAssignedToMe',
OPEN_ACTIVE_FILE: 'gl.openActiveFile',
COPY_LINK_TO_ACTIVE_FILE: 'gl.copyLinkToActiveFile',
OPEN_CURRENT_MERGE_REQUEST: 'gl.openCurrentMergeRequest',
OPEN_CREATE_NEW_ISSUE: 'gl.openCreateNewIssue',
OPEN_CREATE_NEW_MR: 'gl.openCreateNewMR',
OPEN_PROJECT_PAGE: 'gl.openProjectPage',
OPEN_CURRENT_PIPELINE: 'gl.openCurrentPipeline',
PIPELINE_ACTIONS: 'gl.pipelineActions',
ISSUE_SEARCH: 'gl.issueSearch',
MERGE_REQUEST_SEARCH: 'gl.mergeRequestSearch',
PROJECT_ADVANCED_SEARCH: 'gl.projectAdvancedSearch',
COMPARE_CURRENT_BRANCH: 'gl.compareCurrentBranch',
CREATE_SNIPPET: 'gl.createSnippet',
INSERT_SNIPPET: 'gl.insertSnippet',
VALIDATE_CI_CONFIG: 'gl.validateCIConfig',
SHOW_OUTPUT: 'gl.showOutput',
REFRESH_SIDEBAR: 'gl.refreshSidebar',
RESOLVE_THREAD: 'gl.resolveThread',
UNRESOLVE_THREAD: 'gl.unresolveThread',
DELETE_COMMENT: 'gl.deleteComment',
START_EDITING_COMMENT: 'gl.startEditingComment',
CANCEL_EDITING_COMMENT: 'gl.cancelEditingComment',
SUBMIT_COMMENT_EDIT: 'gl.submitCommentEdit',
CREATE_COMMENT: 'gl.createComment',
CHECKOUT_MR_BRANCH: 'gl.checkoutMrBranch',
CLONE_WIKI: 'gl.cloneWiki',
CREATE_SNIPPET_PATCH: 'gl.createSnippetPatch',
SET_TOKEN: 'csdn.setToken',
WEBVIEW: 'csdn.openWebview',
JSON_FORMAT: 'csdn.jsonFormat',
HTTP_REQUEST: 'csdn.httpRequest',
DO_HTTP_REQUEST: 'csdn.doHttpRequest',
REMOVE_TOKEN: 'csdn.removeToken',
SHOW_ISSUES_ASSIGNED_TO_ME: 'csdn.showIssuesAssignedToMe',
SHOW_MERGE_REQUESTS_ASSIGNED_TO_ME: 'csdn.showMergeRequestsAssignedToMe',
OPEN_ACTIVE_FILE: 'csdn.openActiveFile',
COPY_LINK_TO_ACTIVE_FILE: 'csdn.copyLinkToActiveFile',
OPEN_CURRENT_MERGE_REQUEST: 'csdn.openCurrentMergeRequest',
OPEN_CREATE_NEW_ISSUE: 'csdn.openCreateNewIssue',
OPEN_CREATE_NEW_MR: 'csdn.openCreateNewMR',
OPEN_PROJECT_PAGE: 'csdn.openProjectPage',
OPEN_CURRENT_PIPELINE: 'csdn.openCurrentPipeline',
PIPELINE_ACTIONS: 'csdn.pipelineActions',
ISSUE_SEARCH: 'csdn.issueSearch',
MERGE_REQUEST_SEARCH: 'csdn.mergeRequestSearch',
PROJECT_ADVANCED_SEARCH: 'csdn.projectAdvancedSearch',
COMPARE_CURRENT_BRANCH: 'csdn.compareCurrentBranch',
CREATE_SNIPPET: 'csdn.createSnippet',
INSERT_SNIPPET: 'csdn.insertSnippet',
CREATE_NOTE: 'csdn.createNote',
OPEN_NOTE_DOCUMENT: 'csdn.openNoteDocument',
VALIDATE_CI_CONFIG: 'csdn.validateCIConfig',
SHOW_OUTPUT: 'csdn.showOutput',
REFRESH_SIDEBAR: 'csdn.refreshSidebar',
RESOLVE_THREAD: 'csdn.resolveThread',
UNRESOLVE_THREAD: 'csdn.unresolveThread',
DELETE_COMMENT: 'csdn.deleteComment',
START_EDITING_COMMENT: 'csdn.startEditingComment',
CANCEL_EDITING_COMMENT: 'csdn.cancelEditingComment',
SUBMIT_COMMENT_EDIT: 'csdn.submitCommentEdit',
CREATE_COMMENT: 'csdn.createComment',
CHECKOUT_MR_BRANCH: 'csdn.checkoutMrBranch',
CLONE_WIKI: 'csdn.cloneWiki',
CREATE_SNIPPET_PATCH: 'csdn.createSnippetPatch',
OPEN_SNIPPET: 'csdn.openSnippet',
OPEN_PROJECT_SNIPPET: 'csdn.openProjectSnippet',
UTILITY: 'csdn.utilities',
};
/*
User can't trigger these commands directly. We use them from within the code.
*/
export const PROGRAMMATIC_COMMANDS = {
SHOW_RICH_CONTENT: 'gl.showRichContent',
NO_IMAGE_REVIEW: 'gl.noImageReview',
SHOW_RICH_CONTENT: 'csdn.showRichContent',
NO_IMAGE_REVIEW: 'csdn.noImageReview',
};
export const VS_COMMANDS = {
......
import * as vscode from 'vscode';
import * as openers from '../openers';
import * as gitLabService from '../gitlab_service';
import { gitExtensionWrapper } from '../git/git_extension_wrapper';
type VisibilityItem = vscode.QuickPickItem & { type: string };
const PRIVATE_VISIBILITY_ITEM: VisibilityItem = {
label: '$(lock) 私有',
type: 'private',
description: '创建私有笔记',
};
const PUBLIC_VISIBILITY_ITEM: VisibilityItem = {
label: '$(globe) 公开',
type: 'public',
description: '创建公开笔记',
};
export const VISIBILITY_OPTIONS = [PRIVATE_VISIBILITY_ITEM, PUBLIC_VISIBILITY_ITEM];
async function uploadNote(
editor: vscode.TextEditor,
visibility: string,
title?: string
) {
let content = '';
const fileName = editor.document.fileName.split('/').reverse()[0];
const { start, end } = editor.selection;
if (start.line === end.line) {
await vscode.window.showInformationMessage('CSDN Workflow: 您未选取任何内容');
return;
}
const repository = await gitExtensionWrapper.getActiveRepositoryOrSelectOne();
const fileAbsPath = editor.document.uri.path
let fileRelativePath
if (repository && fileAbsPath.indexOf(repository.rootFsPath)!==-1) {
fileRelativePath = fileAbsPath.replace(repository.rootFsPath, ".")
}
const noteTitle = `${fileRelativePath || fileName}#L${start.line}-${end.line}`
const endLine = end.line + 1;
const startPos = new vscode.Position(start.line, 0);
const endPos = new vscode.Position(endLine, 0);
const range = new vscode.Range(startPos, endPos);
content = editor.document.getText(range);
const data = {
title: title || noteTitle,
description: noteTitle,
file_name: fileName,
visibility,
content,
};
const note = await gitLabService.createNote(data);
await openers.openSnippet(note.id);
}
/**
*
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export async function createNote() {
const editor = vscode.window.activeTextEditor;
if (!editor) {
await vscode.window.showInformationMessage('CSDN Workflow: 您需要先打开文件然后选中要添加到笔记的内容,才能执行保存笔记的操作');
return;
}
const title = await vscode.window.showInputBox({
ignoreFocusOut: true,
placeHolder: 'E.g. 图片上传-update.js',
prompt: '代码笔记标题',
});
const visibility = await vscode.window.showQuickPick(VISIBILITY_OPTIONS);
if (!visibility) return;
await uploadNote(editor, visibility.type, title);
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export async function newNoteTextDocument() {
const sampleText = `/**
* 您可在此处书写全新的笔记,然后选择需要保存的内容,执行快捷键:shift+alt+j 保存笔记;
* 也可以在其他已存在内容的文件中,选择要保存的内容,执行快捷键:shift+alt+j 保存笔记。
*/
`
const doc = await vscode.workspace.openTextDocument({ language: 'plaintext', content: sampleText });
await vscode.window.showTextDocument(doc);
}
......@@ -69,7 +69,7 @@ export async function createSnippet() {
const editor = vscode.window.activeTextEditor;
if (!editor) {
await vscode.window.showInformationMessage('GitLab Workflow: No open file.');
await vscode.window.showInformationMessage('CSDN Workflow: No open file.');
return;
}
const repository = await gitExtensionWrapper.getActiveRepositoryOrSelectOne();
......@@ -78,7 +78,7 @@ export async function createSnippet() {
if (!project) {
await vscode.window.showInformationMessage(
'GitLab Workflow: Repository does not contain GitLab project.',
'CSDN Workflow: Repository does not contain GitLab project.',
);
return;
}
......
......@@ -14,7 +14,7 @@ This snippet contains suggested changes for branch ${branch} (commit: ${commit})
Apply this snippet:
- In VS Code with the GitLab Workflow extension installed:
- In VS Code with the CSDN Workflow extension installed:
- Run \`GitLab: Apply snippet patch\` and select this snippet
- Using the \`git\` command:
- Download the \`${patchFileName}\` file to your project folder
......@@ -24,7 +24,7 @@ Apply this snippet:
git apply '${patchFileName}'
~~~
*This snippet was created with the [GitLab Workflow VS Code extension](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow).*
*This snippet was created with the [CSDN Workflow VS Code extension](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow).*
`;
export const createSnippetPatch = async (): Promise<void> => {
......
import * as vscode from 'vscode';
import * as request from 'request-promise';
import { handleError, log } from '../log';
import { UserFriendlyError } from '../errors/user_friendly_error';
import { getUserAgentHeader } from '../utils/get_user_agent_header';
import { USER_COMMANDS } from '../command_names';
async function httpRequest() {
const editor = vscode.window.activeTextEditor;
if (editor) {
const content = editor.document.getText();
try{
const userConfig = JSON.parse(content)
const hmethod: string = userConfig?.http_method?.value || 'GET'
const headers = userConfig?.header?.value || {
"Content-Type": "application/json;charset=utf-8",
...getUserAgentHeader(),
}
const body = userConfig?.body?.value || {}
const url = userConfig.url.value
const proxy = userConfig.proxy.value
await vscode.commands.executeCommand(USER_COMMANDS.SHOW_OUTPUT);
const result = await fetch(url, hmethod, headers, body, proxy)
log(`Response body:\n${result.response}`)
}catch(err){
handleError(
new UserFriendlyError(
'CSDN Workflow: 配置文件解析失败,点击查看详情',
err
),
);
}
}else{
await vscode.window.showInformationMessage('CSDN Workflow: 未找到配置文件,请保持配置文件处于打开状态');
}
}
async function showHttpConfig(): Promise<void> {
// eslint-disable-next-line no-use-before-define
const sampleText = httpConfig()
const doc = await vscode.workspace.openTextDocument({ language: 'json', content: sampleText });
await vscode.window.showTextDocument(doc);
}
async function fetch(url: string, method = 'GET', headers:Record<string, unknown>, data?: Record<string, unknown>, proxy?: string) {
const config: request.RequestPromiseOptions = {
method,
headers
};
if (data) {
config.formData = data;
}
if(proxy){
config.proxy = proxy
}
config.transform = (body, response) => {
try {
return {
response: body,
headers: response.headers,
};
} catch (e) {
handleError(
new UserFriendlyError(
'Failed to parse API response',
e,
`Response body: ${body}\nRequest URL: ${url}`,
),
);
return { error: e };
}
};
return await request(url, config);
}
module.exports = {
showHttpConfig,
httpRequest
}
function httpConfig(): string {
const config = {
"note": "以下内容为 http 请求的临时配置文件,您可以直接进行编辑,我们会根据配置文件内容执行 http 请求。使用快捷键 shift+alt+r 运行。",
"http_method": {
"note": "请求方式,如:GET,POST,DELETE,PUT",
"value": "GET"
},
"header": {
"note": "http headers",
"value": {
"Content-Type": "application/json;charset=utf-8",
...getUserAgentHeader(),
}
},
"body": {
"note": "http body(选填)",
"value": {}
},
"url": {
"note": "请求地址",
"value": "https://codechina.csdn.net/api/v4/templates/gitignores"
},
"proxy": {
"note": "代理设置",
"value": null
}
}
return JSON.stringify(config, null, '\t')
}
import * as vscode from 'vscode';
import { handleError } from '../log';
import { UserFriendlyError } from '../errors/user_friendly_error';
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export async function jsonFormat() {
const editor = vscode.window.activeTextEditor;
if (editor) {
const document = editor?.document
const selection = editor?.selection
const word = document?.getText(selection);
if (word) {
try {
const jsonResult = JSON.parse(word)
const strResult = JSON.stringify(jsonResult, null, '\t')
await editor.edit(editBuilder => {
editBuilder.replace(selection, strResult);
});
} catch (e) {
handleError(
new UserFriendlyError(
'CSDN Workflow: 格式化失败,点击查看详情',
e
),
);
}
} else {
await vscode.window.showInformationMessage('CSDN Workflow: 没有已经选中的 json 内容');
}
}else{
await vscode.window.showInformationMessage('CSDN Workflow: 没有已经打开的文件');
}
}
export const GITLAB_COM_URL = 'https://gitlab.com';
// ~/Library/Application Support/Code/User/settings.json
export const GITLAB_COM_URL = 'https://codechina.csdn.net';
export const REVIEW_URI_SCHEME = 'gl-review';
export const CONFIG_NAMESPACE = 'gitlab';
export const CONFIG_NAMESPACE = 'csdn';
export const CONFIG_CUSTOM_QUERIES = 'customQueries';
export const UTILITIES = 'utilities';
export const EXECUTE_REQUEST_CHILDREN = 'executeRequestChildren';
export const EXECUTE_JSON_CHILDREN = 'executeJsonChildren';
export const ADDED = 'added';
export const DELETED = 'deleted';
export const RENAMED = 'renamed';
......
......@@ -31,7 +31,7 @@ class DataProvider implements vscode.TreeDataProvider<ItemModel | vscode.TreeIte
// eslint-disable-next-line class-methods-use-this
async createPipelineItem(pipeline: RestPipeline | null, project: GitLabProject) {
if (!pipeline) {
return new vscode.TreeItem('No pipeline found');
return new vscode.TreeItem('没有流水线');
}
const statusText = pipeline.status === 'success' ? 'passed' : pipeline.status;
const actions = {
......@@ -53,7 +53,7 @@ class DataProvider implements vscode.TreeDataProvider<ItemModel | vscode.TreeIte
async createMrItem(mr: RestMr | null, repository: WrappedRepository) {
if (!mr) {
return new vscode.TreeItem('No merge request found');
return new vscode.TreeItem('没有合并请求');
}
this.mr = mr;
const item = new MrItemModel(mr, repository);
......@@ -69,7 +69,7 @@ class DataProvider implements vscode.TreeDataProvider<ItemModel | vscode.TreeIte
return issues.map(issue => new IssueItem(issue, repository.rootFsPath));
}
}
return [new vscode.TreeItem('No closing issue found')];
return [new vscode.TreeItem('没有结束的 issue')];
}
async getChildren(item: ItemModel | undefined): Promise<ItemModel[] | vscode.TreeItem[]> {
......
......@@ -46,7 +46,7 @@ export class DataProvider implements vscode.TreeDataProvider<ItemModel | vscode.
logError(e);
return [new ErrorItem('Fetching Issues and MRs failed')];
}
if (repositories.length === 0) return [new vscode.TreeItem('No projects found')];
if (repositories.length === 0) return [new vscode.TreeItem('未发现代码仓库')];
// FIXME: if you are touching this configuration statement, move the configuration to get_extension_configuration.ts
const customQueries =
vscode.workspace
......
import { TreeItem } from 'vscode';
import { PROGRAMMATIC_COMMANDS } from '../../command_names';
// 打开富文本
export class IssueItem extends TreeItem {
constructor(issue: RestIssuable, repositoryPath: string) {
super(`#${issue.iid} · ${issue.title}`);
......
import * as vscode from 'vscode';
import { USER_COMMANDS } from '../../command_names';
export class SnippetItem extends vscode.TreeItem {
constructor(
id: number,
name: string
) {
super(vscode.Uri.file(name));
this.command = {
title: 'Open Snippet',
command: USER_COMMANDS.OPEN_SNIPPET,
arguments: [id],
};
}
}
import * as vscode from 'vscode';
import { USER_COMMANDS } from '../../command_names';
export class UnilityJsonChildrenItem extends vscode.TreeItem {
constructor(
name: string,
type: string,
) {
super(vscode.Uri.file(name));
this.command = {
title: 'Utility Tools',
command: USER_COMMANDS.UTILITY,
arguments: [type],
};
}
}
\ No newline at end of file
import * as vscode from 'vscode';
import { USER_COMMANDS } from '../../command_names';
export class UnilityRequestChildrenItem extends vscode.TreeItem {
constructor(
name: string,
type: string,
) {
super(vscode.Uri.file(name));
this.command = {
title: 'Utility Tools',
command: USER_COMMANDS.UTILITY,
arguments: [type],
};
}
}
\ No newline at end of file
import * as vscode from 'vscode';
import { USER_COMMANDS } from '../../command_names';
import { EXECUTE_JSON_CHILDREN, CONFIG_NAMESPACE, EXECUTE_REQUEST_CHILDREN } from '../../constants';
import { UtilityQuery } from '../../gitlab/utility_query';
import { ItemModel } from './../items/item_model';
import { UnilityJsonChildrenItem } from './unility_json_children_item';
import { UnilityRequestChildrenItem } from './unility_request_children_item';
export class UtilityItem extends ItemModel {
private name: string;
private type: string;
constructor(
name: string,
type: string,
) {
super();
this.name = name;
this.type = type;
}
getTreeItem(): vscode.TreeItem {
const item = new vscode.TreeItem(
this.name,
vscode.TreeItemCollapsibleState.Collapsed,
);
item.iconPath = new vscode.ThemeIcon('filter');
return item;
}
async getChildren(): Promise<UnilityJsonChildrenItem[] | UnilityRequestChildrenItem[]> {
if (this.type == 'json_format'){
const customQueries =
vscode.workspace
.getConfiguration(CONFIG_NAMESPACE)
.get<UtilityQuery[]>(EXECUTE_JSON_CHILDREN) || [];
const items = customQueries.map(q => new UnilityJsonChildrenItem(q.name, q.type));
return items;
}else {
const customQueries =
vscode.workspace
.getConfiguration(CONFIG_NAMESPACE)
.get<UtilityQuery[]>(EXECUTE_REQUEST_CHILDREN) || [];
const items = customQueries.map(q => new UnilityRequestChildrenItem(q.name, q.type));
return items;
}
}
}
import * as vscode from 'vscode';
import * as gitLabService from '../gitlab_service';
import { ErrorItem } from './items/error_item';
import { handleError } from '../log';
import { ItemModel } from './items/item_model';
import { extensionState } from '../extension_state';
import { gitExtensionWrapper } from '../git/git_extension_wrapper';
import { SnippetItem } from './items/snippet_item';
export class DataProvider implements vscode.TreeDataProvider<ItemModel | vscode.TreeItem> {
private eventEmitter = new vscode.EventEmitter<void>();
private disposableChildren: vscode.Disposable[] = [];
onDidChangeTreeData = this.eventEmitter.event;
constructor() {
extensionState.onDidChangeValid(this.refresh, this);
}
async getChildren(item: ItemModel | undefined): Promise<ItemModel[] | vscode.TreeItem[] | undefined> {
if (item) return item.getChildren();
this.disposableChildren.forEach(s => s.dispose());
this.disposableChildren = [];
const repository = gitExtensionWrapper.getActiveRepository();
if (!extensionState.isValid() || !repository) {
return [];
}
try {
const gitlabProject = await repository.getProject();
if (!gitlabProject) {
return [];
}
const projectCodeSnippets = await gitLabService.fetchSnippetForCurrentUser();
if (projectCodeSnippets.length === 0){
return [new vscode.TreeItem('未在当前项目下发现代码笔记')];
}
const snippets = projectCodeSnippets.map((s: RestCodeSnippet) => new SnippetItem(s.id, s.title));
return snippets;
} catch (e) {
handleError(e);
return [new ErrorItem()];
}
}
// eslint-disable-next-line class-methods-use-this
getParent(): null {
return null;
}
// eslint-disable-next-line class-methods-use-this
getTreeItem(item: vscode.TreeItem | ItemModel) {
if (item instanceof ItemModel) return item.getTreeItem();
return item;
}
refresh(): void {
this.eventEmitter.fire();
}
}
import * as vscode from 'vscode';
import * as dayjs from 'dayjs';
import * as relativeTime from 'dayjs/plugin/relativeTime';
import { ItemModel } from './items/item_model';
import { extensionState } from '../extension_state';
dayjs.extend(relativeTime);
class DataProvider implements vscode.TreeDataProvider<ItemModel | vscode.TreeItem> {
private eventEmitter = new vscode.EventEmitter<void>();
onDidChangeTreeData = this.eventEmitter.event;
private mr: RestMr | null = null;
private disposableChildren: vscode.Disposable[] = [];
constructor() {
extensionState.onDidChangeValid(this.refresh, this);
}
async fetchSnippetNote() {
if (this.mr) {
return [new vscode.TreeItem('笔记')];
}
return [new vscode.TreeItem('笔记')];
}
async getChildren(item: ItemModel | undefined): Promise<ItemModel[] | vscode.TreeItem[]> {
if (item) return item.getChildren();
const pipelineItem = await this.fetchSnippetNote();
return [pipelineItem] as vscode.TreeItem[];
}
// eslint-disable-next-line class-methods-use-this
getTreeItem(item: ItemModel | vscode.TreeItem) {
if (item instanceof ItemModel) return item.getTreeItem();
return item;
}
refresh() {
this.eventEmitter.fire();
}
}
exports.DataProvider = DataProvider;
import * as vscode from 'vscode';
import { UtilityItem } from './items/utility_item';
import { UtilityQuery } from '../gitlab/utility_query';
import { ItemModel } from './items/item_model';
import { UTILITIES, CONFIG_NAMESPACE } from '../constants';
import { extensionState } from '../extension_state';
import { gitExtensionWrapper } from '../git/git_extension_wrapper';
import { WrappedRepository } from '../git/wrapped_repository';
async function getAllGitlabRepositories(): Promise<WrappedRepository[]> {
const projectsWithUri = gitExtensionWrapper.repositories.map(async repository => {
await repository.getProject(); // make sure we tried to fetch the project
return repository;
});
return Promise.all(projectsWithUri);
}
export class DataProvider implements vscode.TreeDataProvider<ItemModel | vscode.TreeItem> {
private eventEmitter = new vscode.EventEmitter<void>();
private children: UtilityItem[] = [];
onDidChangeTreeData = this.eventEmitter.event;
constructor() {
extensionState.onDidChangeValid(this.refresh, this);
}
async getChildren(el: ItemModel | undefined): Promise<UtilityItem[] | ItemModel[] | vscode.TreeItem[]> {
if (el) return el.getChildren();
const customQueries =
vscode.workspace
.getConfiguration(CONFIG_NAMESPACE)
.get<UtilityQuery[]>(UTILITIES) || [];
this.children = customQueries.map(q => new UtilityItem(q.name, q.type));
return this.children;
}
// eslint-disable-next-line class-methods-use-this
getParent(): null {
return null;
}
// eslint-disable-next-line class-methods-use-this
getTreeItem(item: vscode.TreeItem | ItemModel) {
if (item instanceof ItemModel) return item.getTreeItem();
return item;
}
refresh(): void {
this.eventEmitter.fire();
}
}
import * as vscode from 'vscode';
import { ItemModel } from './items/item_model';
export class DataProvider implements vscode.TreeDataProvider<ItemModel | vscode.TreeItem> {
private eventEmitter = new vscode.EventEmitter<void>();
private children: ItemModel[] = [];
onDidChangeTreeData = this.eventEmitter.event;
// constructor() {
// extensionState.onDidChangeValid(this.refresh, this);
// }
async getChildren(el: ItemModel | undefined): Promise<ItemModel[] | vscode.TreeItem[]> {
if (el) return el.getChildren();
this.children.forEach(ch => ch.dispose());
this.children = [];
return this.children;
}
// eslint-disable-next-line class-methods-use-this
getParent(): null {
return null;
}
// eslint-disable-next-line class-methods-use-this
getTreeItem(item: vscode.TreeItem | ItemModel) {
if (item instanceof ItemModel) return item.getTreeItem();
return item;
}
refresh(): void {
this.eventEmitter.fire();
}
}
const vscode = require('vscode');
const openers = require('./openers');
const utility = require('./utility');
const tokenInput = require('./token_input');
const { tokenService } = require('./services/token_service');
const tokenServiceWrapper = require('./token_service_wrapper');
......@@ -8,11 +9,18 @@ const pipelineActionsPicker = require('./pipeline_actions_picker');
const searchInput = require('./search_input');
const { createSnippet } = require('./commands/create_snippet');
const { insertSnippet } = require('./commands/insert_snippet');
const { createNote, newNoteTextDocument } = require('./commands/create_note');
const { jsonFormat } = require('./commands/json_format')
const { httpRequest, showHttpConfig } = require('./commands/http_request')
const sidebar = require('./sidebar');
const ciConfigValidator = require('./ci_config_validator');
const { webviewController } = require('./webview_controller');
const { snippetWebviewController } = require('./snippet_webview_controller')
const IssuableDataProvider = require('./data_providers/issuable').DataProvider;
const CurrentBranchDataProvider = require('./data_providers/current_branch').DataProvider;
const SnippetNoteDataProvider = require('./data_providers/snippet_note_data_provider').DataProvider;
// const UtilityToolsDataProvider = require('./data_providers/utility_tools').DataProvider;
const UtilityToolsDataProvider = require('./data_providers/utility').DataProvider;
const { initializeLogging, handleError } = require('./log');
const { GitContentProvider } = require('./review/git_content_provider');
const { REVIEW_URI_SCHEME } = require('./constants');
......@@ -51,6 +59,10 @@ const registerSidebarTreeDataProviders = () => {
const currentBranchDataProvider = new CurrentBranchDataProvider();
const snippetNoteDataProvider = new SnippetNoteDataProvider();
const utilityToolsDataProvider = new UtilityToolsDataProvider()
const register = (name, provider) => {
vscode.window.registerTreeDataProvider(name, provider);
vscode.gitLabWorkflow.sidebarDataProviders.push(provider);
......@@ -58,6 +70,8 @@ const registerSidebarTreeDataProviders = () => {
register('issuesAndMrs', issuableDataProvider);
register('currentBranchInfo', currentBranchDataProvider);
register('snippetNotes', snippetNoteDataProvider);
register('utilityTools', utilityToolsDataProvider);
};
const registerCommands = (context, outputChannel) => {
......@@ -65,6 +79,10 @@ const registerCommands = (context, outputChannel) => {
[USER_COMMANDS.SHOW_ISSUES_ASSIGNED_TO_ME]: openers.showIssues,
[USER_COMMANDS.SHOW_MERGE_REQUESTS_ASSIGNED_TO_ME]: openers.showMergeRequests,
[USER_COMMANDS.SET_TOKEN]: tokenInput.showInput,
[USER_COMMANDS.WEBVIEW]: openers.openSnippet,
[USER_COMMANDS.JSON_FORMAT]: jsonFormat,
[USER_COMMANDS.HTTP_REQUEST]: showHttpConfig,
[USER_COMMANDS.DO_HTTP_REQUEST]: httpRequest,
[USER_COMMANDS.REMOVE_TOKEN]: tokenInput.removeTokenPicker,
[USER_COMMANDS.OPEN_ACTIVE_FILE]: openers.openActiveFile,
[USER_COMMANDS.COPY_LINK_TO_ACTIVE_FILE]: openers.copyLinkToActiveFile,
......@@ -80,6 +98,8 @@ const registerCommands = (context, outputChannel) => {
[USER_COMMANDS.COMPARE_CURRENT_BRANCH]: openers.compareCurrentBranch,
[USER_COMMANDS.CREATE_SNIPPET]: createSnippet,
[USER_COMMANDS.INSERT_SNIPPET]: insertSnippet,
[USER_COMMANDS.CREATE_NOTE]: createNote,
[USER_COMMANDS.OPEN_NOTE_DOCUMENT]: newNoteTextDocument,
[USER_COMMANDS.VALIDATE_CI_CONFIG]: ciConfigValidator.validate,
[USER_COMMANDS.REFRESH_SIDEBAR]: sidebar.refresh,
[PROGRAMMATIC_COMMANDS.SHOW_RICH_CONTENT]: webviewController.open.bind(webviewController),
......@@ -94,6 +114,9 @@ const registerCommands = (context, outputChannel) => {
[USER_COMMANDS.CHECKOUT_MR_BRANCH]: checkoutMrBranch,
[USER_COMMANDS.CLONE_WIKI]: cloneWiki,
[USER_COMMANDS.CREATE_SNIPPET_PATCH]: createSnippetPatch,
[USER_COMMANDS.OPEN_SNIPPET]: openers.openSnippet,
[USER_COMMANDS.OPEN_PROJECT_SNIPPET]: openers.openProjectSnippet,
[USER_COMMANDS.UTILITY]: utility.executeCommand,
[PROGRAMMATIC_COMMANDS.NO_IMAGE_REVIEW]: () =>
vscode.window.showInformationMessage("GitLab MR review doesn't support images yet."),
};
......@@ -119,12 +142,13 @@ const registerCiCompletion = context => {
* @param {vscode.ExtensionContext} context
*/
const activate = context => {
const outputChannel = vscode.window.createOutputChannel('GitLab Workflow');
const outputChannel = vscode.window.createOutputChannel('CSDN Workflow');
initializeLogging(line => outputChannel.appendLine(line));
vscode.workspace.registerTextDocumentContentProvider(REVIEW_URI_SCHEME, new GitContentProvider());
registerCommands(context, outputChannel);
const isDev = process.env.NODE_ENV === 'development';
webviewController.init(context, isDev);
snippetWebviewController.init(context);
tokenService.init(context);
tokenServiceWrapper.init(context);
extensionState.init(tokenService);
......
......@@ -4,6 +4,7 @@ import { TokenService } from './services/token_service';
import { gitExtensionWrapper } from './git/git_extension_wrapper';
const hasOpenRepositories = (): boolean => gitExtensionWrapper.repositories.length > 0;
const hasInstanceRemote = (): boolean => gitExtensionWrapper.repositories.map(r=>r.instanceUrl).length > 0
export class ExtensionState {
private changeValidEmitter = new vscode.EventEmitter<void>();
......@@ -37,7 +38,10 @@ export class ExtensionState {
'gitlab:noRepository',
!hasOpenRepositories(),
);
await vscode.commands.executeCommand('setContext', 'gitlab:noInstanceRemote', !hasInstanceRemote());
await vscode.commands.executeCommand('setContext', 'gitlab:validState', this.isValid());
await vscode.commands.executeCommand('setContext', 'gitlab:noTokens', !this.hasAnyTokens());
await vscode.commands.executeCommand('setContext', 'gitlab:hasAnyToken', this.hasAnyTokens());
if (this.lastValid !== this.isValid()) {
this.lastValid = this.isValid();
this.changeValidEmitter.fire();
......
export interface UtilityQuery {
name: string;
type: string;
}
import * as vscode from 'vscode';
import * as request from 'request-promise';
import * as assert from 'assert';
import { tokenService } from './services/token_service';
import { UserFriendlyError } from './errors/user_friendly_error';
import { ApiError } from './errors/api_error';
......@@ -14,6 +13,7 @@ import { getInstanceUrl } from './utils/get_instance_url';
import { GitLabProject } from './gitlab/gitlab_project';
import { gitExtensionWrapper } from './git/git_extension_wrapper';
import { getExtensionConfiguration } from './utils/get_extension_configuration';
import { GITLAB_COM_URL } from './constants';
export interface RestJob {
name: string;
......@@ -51,7 +51,7 @@ async function fetch(
if (!glToken) {
let err = `
GitLab Workflow: Cannot make request.
CSDN Workflow: Cannot make request.
GitLab URL for this workspace is set to ${instanceUrl}
and there is no matching token for this URL.
`;
......@@ -98,6 +98,70 @@ async function fetch(
return await request(`${apiRoot}${path}`, config);
}
async function userFetch(
path: string,
method = 'GET',
data?: Record<string, unknown>,
notParseJson?: boolean
) {
const instanceUrl = GITLAB_COM_URL;
const apiRoot = `${instanceUrl}/api/v4`;
const glToken = tokenService.getToken(instanceUrl);
const tokens = tokenService.getInstanceUrls().join(', ');
if (!glToken) {
let err = `
CSDN Workflow: 无法执行此操作,没有读取用户登陆信息
`;
if (tokens.length) {
err = `${err} You have configured tokens for ${tokens}.`;
}
await vscode.window.showInformationMessage(err);
throw new Error(err);
}
const config: request.RequestPromiseOptions = {
method,
headers: {
'PRIVATE-TOKEN': glToken,
...getUserAgentHeader(),
},
...getHttpAgentOptions(),
};
if (data) {
config.formData = data;
}
config.transform = (body, response) => {
try {
if (notParseJson) {
return {
response: body,
headers: response.headers,
};
}
return {
response: JSON.parse(body),
headers: response.headers,
};
} catch (e) {
handleError(
new UserFriendlyError(
'Failed to parse API response',
e,
`Response body: ${body}\nRequest URL: ${apiRoot}${path}`,
),
);
return { error: e };
}
};
return await request(`${apiRoot}${path}`, config);
}
async function fetchCurrentProject(repositoryRoot: string): Promise<GitLabProject | null> {
try {
const repository = gitExtensionWrapper.getRepository(repositoryRoot);
......@@ -155,6 +219,7 @@ async function fetchFirstUserByUsername(repositoryRoot: string, userName: string
}
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export async function fetchVersion(repositoryRoot: string) {
try {
if (!versionCache) {
......@@ -189,6 +254,7 @@ async function fetchLastPipelineForCurrentBranch(
type QueryValue = string | boolean | string[] | number | undefined;
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export async function fetchIssuables(params: CustomQuery, repositoryRoot: string) {
const { type, scope, state, author, assignee, wip } = params;
let { searchIn, pipelineId, reviewer } = params;
......@@ -349,6 +415,7 @@ export async function fetchIssuables(params: CustomQuery, repositoryRoot: string
return issuable.map(normalizeAvatarUrl(await getInstanceUrl(repositoryRoot)));
}
export async function fetchLastJobsForCurrentBranch(
repositoryRoot: string,
pipeline: RestPipeline,
......@@ -429,6 +496,7 @@ export async function fetchPipelineAndMrForCurrentBranch(
*
* @param {string} action create|retry|cancel
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export async function handlePipelineAction(action: string, repositoryRoot: string) {
const { pipeline } = await fetchPipelineAndMrForCurrentBranch(repositoryRoot);
const project = await fetchCurrentProjectSwallowError(repositoryRoot);
......@@ -450,7 +518,7 @@ export async function handlePipelineAction(action: string, repositoryRoot: strin
throw new UserFriendlyError(`Failed to ${action} pipeline.`, e);
}
} else {
await vscode.window.showErrorMessage('GitLab Workflow: No project or pipeline found.');
await vscode.window.showErrorMessage('CSDN Workflow: No project or pipeline found.');
return undefined;
}
}
......@@ -475,6 +543,7 @@ export async function fetchMRIssues(mrId: number, repositoryRoot: string): Promi
}
// TODO specify the correct interface when we convert `create_snippet.js`
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export async function createSnippet(repositoryRoot: string, data: { id: number }) {
try {
const { response } = await fetch(repositoryRoot, `/projects/${data.id}/snippets`, 'POST', data);
......@@ -483,6 +552,57 @@ export async function createSnippet(repositoryRoot: string, data: { id: number }
throw new UserFriendlyError('Failed to create your snippet.', e);
}
}
// 创建笔记
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export async function createNote(data: { content: string }) {
try {
const { response } = await userFetch(`/snippets`, 'POST', data);
return response;
} catch (e) {
throw new UserFriendlyError('Failed to create your snippet.', e);
}
}
async function fetchSnippetContent(snippetId: number, filePath: string): Promise<CodeSnippetFile> {
const fileContent: CodeSnippetFile = {
size: 0,
file_path: filePath,
content: ''
}
try {
const { response, headers: { 'content-length': size } } = await userFetch(`/snippets/${snippetId}/files/master/${filePath}/raw`, 'GET', undefined, true);
fileContent.size = size
fileContent.content = response
return fileContent
} catch (e) {
return fileContent
}
}
export async function fetchSnippet(snippetId: number): Promise<RestCodeSnippet> {
const { response } = await userFetch(`/snippets/${snippetId}`, 'GET');
console.log(response)
try {
const snippet: RestCodeSnippet = {
id: snippetId,
author: response.author,
file_name: response.file_name,
title: response.title,
web_url: response.web_url,
visibility: response.visibility,
description: response.description,
ssh_url_to_repo: response.ssh_url_to_repo,
http_url_to_repo: response.http_url_to_repo,
updated_at: response.updated_at
}
snippet.files = await Promise.all(response.files.map(async (f: SnippetFile) => {
return fetchSnippetContent(snippetId, f.path)
}))
return snippet;
} catch (e) {
throw new UserFriendlyError('Failed to open this snippet.', e);
}
}
interface ValidationResponse {
status?: string;
......@@ -505,6 +625,7 @@ export async function validateCIConfig(
}
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export async function renderMarkdown(markdown: string, repositoryRoot: string) {
let rendered = { html: markdown };
const version = await fetchVersion(repositoryRoot);
......@@ -532,3 +653,34 @@ export async function renderMarkdown(markdown: string, repositoryRoot: string) {
return rendered.html;
}
export async function fetchSnippetForCurrentProject(
repositoryRoot: string,
): Promise<Array<RestCodeSnippet> | []> {
const project = await fetchCurrentProject(repositoryRoot);
let projectCodeSnippets = [];
const path = `/projects/${project?.restId}/snippets`;
const { response } = await fetch(repositoryRoot, path);
projectCodeSnippets = response;
if (projectCodeSnippets.length > 0) {
return projectCodeSnippets;
}
return [];
}
export async function fetchSnippetForCurrentUser(): Promise<Array<RestCodeSnippet> | []> {
let projectCodeSnippets = [];
const path = `/snippets`;
const { response } = await userFetch(path);
projectCodeSnippets = response;
if (projectCodeSnippets.length > 0) {
return projectCodeSnippets;
}
return [];
}
......@@ -6,6 +6,7 @@ import { handleError } from './log';
import { VS_COMMANDS } from './command_names';
import { gitExtensionWrapper } from './git/git_extension_wrapper';
import { WrappedRepository } from './git/wrapped_repository';
import { snippetWebviewController } from './snippet_webview_controller'
export const openUrl = async (url: string): Promise<void> =>
vscode.commands.executeCommand(VS_COMMANDS.OPEN, vscode.Uri.parse(url));
......@@ -48,7 +49,7 @@ export async function showMergeRequests(): Promise<void> {
async function getActiveFile() {
const editor = vscode.window.activeTextEditor;
if (!editor) {
await vscode.window.showInformationMessage('GitLab Workflow: No open file.');
await vscode.window.showInformationMessage('CSDN Workflow: No open file.');
return undefined;
}
......@@ -56,7 +57,7 @@ async function getActiveFile() {
if (!repository) {
await vscode.window.showInformationMessage(
'GitLab Workflow: Open file isn’t part of a repository.',
'CSDN Workflow: Open file isn’t part of a repository.',
);
return undefined;
}
......@@ -148,3 +149,12 @@ export async function compareCurrentBranch(): Promise<void> {
await openUrl(`${project.webUrl}/compare/master...${repository.lastCommitSha}`);
}
}
export async function openSnippet(snippetId: number): Promise<void> {
const snippet = await gitLabService.fetchSnippet(snippetId);
await snippetWebviewController.open(snippet);
}
export async function openProjectSnippet(snippetId: number): Promise<void> {
await openTemplatedLink('$projectUrl/snippets/$snippetId');
}
......@@ -7,7 +7,7 @@ const { instance: statusBar } = require('./status_bar');
async function showPicker() {
const items = [
{
label: 'View latest pipeline on GitLab',
label: 'View latest pipeline on CSDN',
action: 'view',
},
{
......
import * as fs from 'fs';
import * as path from 'path';
import * as vscode from 'vscode';
import * as assert from 'assert';
import * as crypto from 'crypto';
import * as cheerio from 'cheerio';
import * as timeago from 'timeago.js';
import * as hljs from 'highlight.js';
import * as marked from 'marked';
class SnippetWebviewController {
context?: vscode.ExtensionContext;
openedPanels: Record<string, vscode.WebviewPanel | undefined> = {};
hash?: string;
init(context: vscode.ExtensionContext) {
this.context = context;
}
private getIndexPath() {
assert(this.context);
return 'src/webview/public/index.html';
}
private replaceResources() {
assert(this.context);
const nonce = crypto.randomBytes(20).toString('hex');
this.hash = nonce;
return fs
.readFileSync(path.join((this.context?.extensionPath || './'), this.getIndexPath()), 'UTF-8')
.replace(/{{nonce}}/gm, this.hash)
}
private createPanel(snippet: RestCodeSnippet) {
assert(this.context);
const title = `${snippet.title.slice(0, 20)}...`;
return vscode.window.createWebviewPanel('glWorkflow', title, vscode.ViewColumn.One, {
enableScripts: true,
localResourceRoots: [vscode.Uri.file(path.join((this.context?.extensionPath || './'), 'src'))],
retainContextWhenHidden: true,
});
}
async open(snippet: RestCodeSnippet) {
const panelKey = `snippets-${snippet.id}`;
const openedPanel = this.openedPanels[panelKey];
if (openedPanel) {
openedPanel.reveal();
return openedPanel;
}
const newPanel = await this.create(snippet);
this.openedPanels[panelKey] = newPanel;
newPanel.onDidDispose(() => {
this.openedPanels[panelKey] = undefined;
});
newPanel.webview.onDidReceiveMessage(
async message => {
switch (message.command) {
case 'copySnippet':
await this.copySnippet((snippet.files || []), message.text);
break;
case 'copyShareLink':
await this.copyShareLink(snippet.web_url)
break;
default:
break;
}
}
);
return newPanel;
}
private async create(snippet: RestCodeSnippet) {
assert(this.context);
const panel = this.createPanel(snippet);
const html = this.replaceResources();
panel.webview.html = this.fillInApp(html, this.getSnippetHtml(snippet));
return panel;
}
getSnippetHtml(snippet: RestCodeSnippet): string {
assert(this.context)
const snippetStyle = fs.readFileSync(path.join((this.context?.extensionPath || './'), 'src/assets/styles/snippet.css'), 'UTF-8').toString()
const html = `
<style>${snippetStyle}</style>
${this.getSnippetHeaderHtml(snippet)}
<h1 class="snippet_title">${snippet.title}</h1>
<div class="snippet_desc md_preview">${this.marked(snippet.description)}</div>
${this.getSnippetFileHtml(snippet.files || [])}
`
return html
}
highlightCode(content: string) {
assert(this.context);
if (!content) return ''
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const highlightContent = (hljs as any).highlightAuto(content).value;
return this.generateCodeLineNum(highlightContent);
}
marked(content: string) {
assert(this.context);
if (!content) return ''
marked.setOptions({
breaks: false,
gfm: true,
langPrefix: "language-",
// eslint-disable-next-line func-names
'highlight': function (code) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const html = (hljs as any).highlightAuto(code).value;
return html;
}
});
const html = marked(content); // 解析markdown
return html
}
generateCodeLineNum(content: string) {
assert(this.context);
if (!content) return ''
return `<ul><li>${content.replace(/\n/g, "\n</li><li>")}\n</li></ul>`
}
getSnippetHeaderHtml(snippet: RestCodeSnippet): string {
assert(this.context)
const {
author: { avatar_url: avatar, name },
updated_at: updatedAt,
web_url: url
} = snippet
const html = `
<header class="snippet_header">
<img src="${avatar}">
<span class="flex-1">
${timeago.format(updatedAt, 'zh_CN')}由 <b>${name}</b> 创建
</span>
<a href="${url}">在 CSDN 中打开并查看</a>
<a href="javascript:void(0)" id="shareLink">分享</a>
</header>
<script nonce="${this.hash}">
document.getElementById("shareLink").onclick = function() {
vscode.postMessage({
command: 'copyShareLink',
text: ''
})
}
</script>
`
// <a>编辑</a>
// <a>删除</a>
return html
}
getSnippetFileHtml(files: CodeSnippetFile[]): string {
assert(this.context)
const hightlightStyle = fs.readFileSync(path.join((this.context?.extensionPath || './'), 'src/assets/styles/highlight-dark.css'), 'UTF-8').toString()
const mdStyle = fs.readFileSync(path.join((this.context?.extensionPath || './'), 'src/assets/styles/marked.css'), 'UTF-8').toString()
return `
<style>
${hightlightStyle}
${mdStyle}
</style>
<div id="snippet_list">
${files.map((f, i) => {
const isMd = f.file_path.split('.').pop() === 'md'
return `
<div class="snippet_item_container">
<div class="snippet_item_header">
<div class="snippet_item_title">${f.file_path}</div>
<div class="snippet_item_size">${f.size}字节</div>
<a href="javascript:void(0)" data-index="${i}" class="snippet_item_copy">复制代码</a>
</div>
<div class="snippet_item_body">
<div class="snippet_content">
${isMd ? `<div class="md_preview">${this.marked(f.content)}</div>` : `<pre><code class="hljs">${this.highlightCode(f.content)}</code></pre>`}
</div>
</div>
</div>`
}).join('')}
</div>
<script nonce="${this.hash}">
const vscode = acquireVsCodeApi();
document.getElementById("snippet_list").addEventListener("click", function(e) {
const target = e.target || e.srcElement
const snippetIndex = target.dataset.index
vscode.postMessage({
command: 'copySnippet',
text: snippetIndex
})
})
</script>
`
}
async copySnippet(files: CodeSnippetFile[], index: number) {
assert(this.context);
const snippetContent = files[index]?.content
await vscode.env.clipboard.writeText(snippetContent)
await vscode.window.showInformationMessage('代码已复制到剪切板')
}
async copyShareLink(link: string) {
assert(this.context);
await vscode.env.clipboard.writeText(link)
await vscode.window.showInformationMessage('分享链接已复制到剪切板')
}
fillInApp(templateHtml: string, html: string): string {
assert(this.context)
const $ = cheerio.load(templateHtml)
$('div#app').html(html)
return $.html()
}
}
export const snippetWebviewController = new SnippetWebviewController();
......@@ -15,7 +15,7 @@ const {
showIssueLinkOnStatusBar,
showMrStatusOnStatusBar,
showPipelineUpdateNotifications,
} = vscode.workspace.getConfiguration('gitlab');
} = vscode.workspace.getConfiguration('csdn');
const iconForStatus: Record<string, { icon: string; text?: string } | undefined> = {
running: { icon: 'pulse' },
......@@ -71,7 +71,7 @@ export class StatusBar {
firstRun = true;
async refresh() {
async refresh(): Promise<void> {
const repository = gitExtensionWrapper.getActiveRepository();
if (!repository) return;
......@@ -100,7 +100,7 @@ export class StatusBar {
async updatePipelineItem(pipeline: RestPipeline | null, repositoryRoot: string): Promise<void> {
if (!this.pipelineStatusBarItem) return;
if (!pipeline) {
this.pipelineStatusBarItem.text = 'GitLab: No pipeline.';
this.pipelineStatusBarItem.text = 'CSDN: No pipeline.';
this.pipelineStatusBarItem.show();
this.firstRun = false;
return;
......@@ -119,7 +119,7 @@ export class StatusBar {
}
}
const msg = `$(${iconForStatus[status]?.icon}) GitLab: Pipeline ${statusText}`;
const msg = `$(${iconForStatus[status]?.icon}) CSDN: Pipeline ${statusText}`;
if (
showPipelineUpdateNotifications &&
......@@ -146,12 +146,12 @@ export class StatusBar {
if (!this.mrIssueStatusBarItem) return;
if (mr) {
const issues = await gitLabService.fetchMRIssues(mr.iid, repositoryRoot);
let text = `$(code) GitLab: No issue.`;
let text = `$(code) CSDN: No issue.`;
let command;
const firstIssue = issues[0];
if (firstIssue) {
text = `$(code) GitLab: Issue #${firstIssue.iid}`;
text = `$(code) CSDN: Issue #${firstIssue.iid}`;
command = openIssuableOnTheWebCommand(firstIssue);
}
......@@ -169,21 +169,21 @@ export class StatusBar {
? openIssuableOnTheWebCommand(mr)
: USER_COMMANDS.OPEN_CREATE_NEW_MR;
this.mrStatusBarItem.text = mr
? `$(git-pull-request) GitLab: MR !${mr.iid}`
: '$(git-pull-request) GitLab: Create MR.';
? `$(git-pull-request) CSDN: MR !${mr.iid}`
: '$(git-pull-request) CSDN: Create MR.';
}
async init() {
async init(): Promise<void> {
if (showStatusBarLinks) {
this.pipelineStatusBarItem = createStatusBarItem(
'$(info) GitLab: Fetching pipeline...',
'$(info) CSDN: Fetching pipeline...',
USER_COMMANDS.PIPELINE_ACTIONS,
);
if (showMrStatusOnStatusBar) {
this.mrStatusBarItem = createStatusBarItem('$(info) GitLab: Finding MR...');
this.mrStatusBarItem = createStatusBarItem('$(info) CSDN: Finding MR...');
if (showIssueLinkOnStatusBar) {
this.mrIssueStatusBarItem = createStatusBarItem(
'$(info) GitLab: Fetching closing issue...',
'$(info) CSDN: Fetching closing issue...',
);
}
}
......@@ -195,7 +195,7 @@ export class StatusBar {
}
}
dispose() {
dispose(): void {
if (showStatusBarLinks) {
this.pipelineStatusBarItem?.dispose();
......
......@@ -3,21 +3,15 @@ const { GITLAB_COM_URL } = require('./constants');
const { tokenService } = require('./services/token_service');
async function showInput() {
const instance = await vscode.window.showInputBox({
ignoreFocusOut: true,
value: GITLAB_COM_URL,
placeHolder: 'E.g. https://gitlab.com',
prompt: 'URL to Gitlab instance',
});
const token = await vscode.window.showInputBox({
ignoreFocusOut: true,
password: true,
placeHolder: 'Paste your GitLab Personal Access Token...',
placeHolder: '请在此处粘贴您在 CSDN codechina 平台的用户访问令牌',
});
if (instance && token) {
await tokenService.setToken(instance, token);
if (token) {
await tokenService.setToken(GITLAB_COM_URL, token);
}
}
......@@ -25,7 +19,7 @@ async function removeTokenPicker() {
const instanceUrls = tokenService.getInstanceUrls();
const selectedInstanceUrl = await vscode.window.showQuickPick(instanceUrls, {
ignoreFocusOut: true,
placeHolder: 'Select Gitlab instance for PAT removal',
placeHolder: '点击 URL 以确认删除用户访问令牌',
});
if (selectedInstanceUrl) {
......
......@@ -8,7 +8,7 @@ let active = false;
// FIXME: if you are touching this configuration statement, move the configuration to get_extension_configuration.ts
const currentInstanceUrl = () =>
vscode.workspace.getConfiguration('gitlab').instanceUrl || GITLAB_COM_URL;
vscode.workspace.getConfiguration('csdn').instanceUrl || GITLAB_COM_URL;
const getToken = () => tokenService.getToken(currentInstanceUrl());
......@@ -27,7 +27,7 @@ const updateExtensionStatus = () => {
const watchConfigurationChanges = () => {
vscode.workspace.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('gitlab')) {
if (e.affectsConfiguration('csdn')) {
updateExtensionStatus();
}
});
......
......@@ -28,13 +28,6 @@ interface RestMr extends RestIssuable {
source_branch: string;
}
interface RestMrVersion {
head_commit_sha: string;
base_commit_sha: string;
start_commit_sha: string;
diffs: RestDiffFile[];
}
interface RestDiffFile {
new_path: string;
old_path: string;
......@@ -44,6 +37,13 @@ interface RestDiffFile {
diff: string;
}
interface RestMrVersion {
head_commit_sha: string;
base_commit_sha: string;
start_commit_sha: string;
diffs: RestDiffFile[];
}
interface RestVulnerability {
location?: {
file: string;
......@@ -68,3 +68,37 @@ interface RestUser {
email: string;
state: string;
}
interface CodeSnippetFile {
size: number,
file_path: string;
content: string;
}
interface SnippetFile {
size: number,
path: string;
raw_url: string;
}
interface SnippetAuthor {
id: number;
name: string;
user_name: string;
avatar_url: string;
web_url: string;
}
interface RestCodeSnippet {
id: number;
author: SnippetAuthor;
file_name: string;
title: string;
web_url: string;
visibility: string;
description: string;
files?: CodeSnippetFile[];
ssh_url_to_repo?: string;
http_url_to_repo?: string;
updated_at: Date;
}
import * as vscode from 'vscode';
import { USER_COMMANDS} from './command_names';
export const executeCommand = async (type: string): Promise<void> =>
vscode.commands.executeCommand(await getCommandByType(type));
async function getCommandByType(type: string) : Promise<string> {
if (type === 'json_format'){
return USER_COMMANDS.JSON_FORMAT;
}
if (type === 'execute_this_request'){
return USER_COMMANDS.DO_HTTP_REQUEST;
}
if (type === 'config_file'){
return USER_COMMANDS.HTTP_REQUEST;
}
return '';
}
......@@ -15,7 +15,7 @@ export const getHttpAgentOptions = (): GitLabHttpAgentOptions => {
const result: GitLabHttpAgentOptions = {};
// FIXME: if you are touching this configuration statement, move the configuration to get_extension_configuration.ts
const { ignoreCertificateErrors, ca, cert, certKey } = vscode.workspace.getConfiguration(
'gitlab',
'csdn',
);
result.rejectUnauthorized = !ignoreCertificateErrors;
......
......@@ -2,12 +2,12 @@ import * as vscode from 'vscode';
export const getUserAgentHeader = (): Record<string, string> => {
const extension = vscode.extensions.getExtension('GitLab.gitlab-workflow');
const extensionVersion = extension?.packageJSON?.version;
const extensionVersion = extension?.packageJSON?.version || "default";
const nodePlatform = `Node.js/${process.version.substr(1)} (${process.platform}; ${
process.arch
})`;
const vsCodeVersion = vscode.version;
return {
'User-Agent': `vs-code-gitlab-workflow/${extensionVersion} VSCode/${vsCodeVersion} ${nodePlatform}`,
'User-Agent': `vs-code-csdn-workflow/${extensionVersion} VSCode/${vsCodeVersion} ${nodePlatform}`,
};
};
......@@ -2259,17 +2259,6 @@
"color-convert": "^2.0.1"
}
},
"chalk": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
"integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
"dev": true,
"optional": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"cliui": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
......@@ -2302,31 +2291,12 @@
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
"optional": true
},
"is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true
},
"loader-utils": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
"integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
"dev": true,
"optional": true,
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^2.1.2"
}
},
"ssri": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz",
......@@ -2347,28 +2317,6 @@
"strip-ansi": "^6.0.0"
}
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"optional": true,
"requires": {
"has-flag": "^4.0.0"
}
},
"vue-loader-v16": {
"version": "npm:vue-loader@16.2.0",
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.2.0.tgz",
"integrity": "sha512-TitGhqSQ61RJljMmhIGvfWzJ2zk9m1Qug049Ugml6QP3t0e95o0XJjk29roNEiPKJQBEi8Ord5hFuSuELzSp8Q==",
"dev": true,
"optional": true,
"requires": {
"chalk": "^4.1.0",
"hash-sum": "^2.0.0",
"loader-utils": "^2.0.0"
}
},
"wrap-ansi": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
......@@ -13945,6 +13893,87 @@
}
}
},
"vue-loader-v16": {
"version": "npm:vue-loader@16.5.0",
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.5.0.tgz",
"integrity": "sha512-WXh+7AgFxGTgb5QAkQtFeUcHNIEq3PGVQ8WskY5ZiFbWBkOwcCPRs4w/2tVyTbh2q6TVRlO3xfvIukUtjsu62A==",
"dev": true,
"optional": true,
"requires": {
"chalk": "^4.1.0",
"hash-sum": "^2.0.0",
"loader-utils": "^2.0.0"
},
"dependencies": {
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"optional": true,
"requires": {
"color-convert": "^2.0.1"
}
},
"chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
"optional": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"optional": true,
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true,
"optional": true
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
"optional": true
},
"loader-utils": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
"integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
"dev": true,
"optional": true,
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^2.1.2"
}
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"optional": true,
"requires": {
"has-flag": "^4.0.0"
}
}
}
},
"vue-resize": {
"version": "0.4.5",
"resolved": "https://registry.npmjs.org/vue-resize/-/vue-resize-0.4.5.tgz",
......
......@@ -2,9 +2,10 @@
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src vscode-resource: https:; script-src 'nonce-{{nonce}}' 'unsafe-eval'; style-src 'unsafe-inline';">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src vscode-resource: https:; script-src 'nonce-{{nonce}}' 'unsafe-eval'; style-src 'unsafe-inline' 'nonce-{{nonce}}';">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>GitLab Workflow</title>
<title>CSDN Workflow</title>
<link nonce="{{nonce}}" href="{{styleUri}}" rel="stylesheet" type="text/css">
</head>
<body>
<div id="app"></div>
......
......@@ -4,7 +4,7 @@
<meta charset="utf-8">
<meta http-equiv="Content-Security-Policy" content="img-src vscode-resource: https:; script-src 'nonce-{{nonce}}';">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>GitLab Workflow</title>
<title>CSDN Workflow</title>
<link href="{{styleUri}}" rel="stylesheet" type="text/css">
</head>
<body>
......
export default {
gitLabLogo:
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M29.782 199.732L256 493.714 8.074 309.699c-6.856-5.142-9.712-13.996-7.141-21.993l28.849-87.974zm75.405-174.806c-3.142-8.854-15.709-8.854-18.851 0L29.782 199.732h131.961L105.187 24.926zm56.556 174.806L256 493.714l94.257-293.982H161.743zm349.324 87.974l-28.849-87.974L256 493.714l247.926-184.015c6.855-5.142 9.711-13.996 7.141-21.993zm-85.404-262.78c-3.142-8.854-15.709-8.854-18.851 0l-56.555 174.806h131.961L425.663 24.926z"></path></svg>',
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="currentColor" d="M 12.767 12.046 C 12.608 11.896 12.399 11.814 12.183 11.816 C 11.972 11.817 11.776 11.909 11.636 12.066 C 10.404 13.478 8.26 13.631 7.384 13.631 C 5.779 13.631 4.55 13.222 3.733 12.419 C 2.955 11.656 2.546 10.534 2.524 9.08 C 2.469 5.713 4.372 2.23 7.671 2.23 C 9.248 2.23 10.468 3.346 10.921 3.829 C 11.075 3.994 11.289 4.09 11.52 4.092 C 11.741 4.099 11.953 4.002 12.095 3.834 L 12.221 3.681 C 12.482 3.37 12.605 2.96 12.554 2.556 C 12.505 2.132 12.292 1.744 11.961 1.473 C 10.801 0.51 9.336 -0.014 7.826 0 C 5.796 0 3.792 0.934 2.326 2.565 C 0.78 4.277 -0.043 6.608 0.002 9.125 C 0.037 11.145 0.7 12.846 1.92 14.04 C 3.227 15.325 5.14 16 7.462 16 C 10.184 16 11.872 15.193 12.807 14.519 C 13.168 14.255 13.389 13.841 13.402 13.394 C 13.414 12.928 13.229 12.48 12.886 12.162 Z"/></path></svg>',
label:
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="currentColor" d="M15 1H9.828a2 2 0 0 0-1.414.586L1.586 8.414a2 2 0 0 0 0 2.828l3.172 3.172a2 2 0 0 0 2.828 0l6.828-6.828A2 2 0 0 0 15 6.172V1zm-4 5a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"></path></svg>',
comment_dots:
......
......@@ -68,7 +68,7 @@ export default {
by
<user-avatar :user="issuable.author" :show-handle="false" />
<a :href="issuable.web_url" class="view-link">
Open in GitLab
在 CSDN 中打开并查看
</a>
</div>
<div class="title">
......
此差异已折叠。
......@@ -58,7 +58,7 @@ describe('Validate CI config', async () => {
const informationMessageMock = sandbox
.mock(vscode.window)
.expects('showInformationMessage')
.withArgs('GitLab Workflow: Your CI configuration is valid.')
.withArgs('CSDN Workflow: Your CI configuration is valid.')
.resolves();
await insertTextIntoActiveEditor(VALID_CI_CONFIG);
......@@ -78,7 +78,7 @@ describe('Validate CI config', async () => {
assert.deepStrictEqual(errorMessages, [
'jobs:test config contains unknown keys: scccript',
'GitLab Workflow: Invalid CI configuration.',
'CSDN Workflow: Invalid CI configuration.',
]);
});
});
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册