├── .gitattributes
├── .gitignore
├── .testignore
├── .vscode
├── extensions.json
├── launch.json
├── settings.json
└── tasks.json
├── .vscodeignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── ThirdPartyNotices.txt
├── assets
├── Preview.svg
├── PreviewOnRightPane_16x.svg
├── PreviewOnRightPane_16x_dark.svg
├── Preview_inverse.svg
├── ViewSource.svg
├── ViewSource_inverse.svg
├── images
│ ├── ui-bg_diagonals-thick_18_b81900_40x40.png
│ ├── ui-bg_diagonals-thick_20_666666_40x40.png
│ ├── ui-bg_flat_10_000000_40x100.png
│ ├── ui-bg_glass_100_f6f6f6_1x400.png
│ ├── ui-bg_glass_100_fdf5ce_1x400.png
│ ├── ui-bg_glass_65_ffffff_1x400.png
│ ├── ui-bg_gloss-wave_35_f6a828_500x100.png
│ ├── ui-bg_highlight-soft_100_eeeeee_1x100.png
│ ├── ui-bg_highlight-soft_75_ffe45c_1x100.png
│ ├── ui-icons_222222_256x240.png
│ ├── ui-icons_228ef1_256x240.png
│ ├── ui-icons_ef8c08_256x240.png
│ ├── ui-icons_ffd27a_256x240.png
│ └── ui-icons_ffffff_256x240.png
├── jquery-ui.min.css
├── pytutor.common.css
└── pytutor.theme.css
├── gulpfile.js
├── images
├── previewDemo.gif
└── settingDemo.gif
├── package-lock.json
├── package.json
├── package.nls.json
├── package.nls.zh-cn.json
├── package.nls.zh-tw.json
├── preview-src
├── README.md
├── datas.ts
├── events.ts
├── index.ts
├── lib
│ ├── d3.v2.min.js
│ ├── jquery-3.0.0.min.js
│ ├── jquery-ui-1.11.4
│ │ ├── external
│ │ │ └── jquery
│ │ │ │ └── jquery.js
│ │ ├── images
│ │ │ ├── ui-bg_diagonals-thick_18_b81900_40x40.png
│ │ │ ├── ui-bg_diagonals-thick_20_666666_40x40.png
│ │ │ ├── ui-bg_flat_10_000000_40x100.png
│ │ │ ├── ui-bg_glass_100_f6f6f6_1x400.png
│ │ │ ├── ui-bg_glass_100_fdf5ce_1x400.png
│ │ │ ├── ui-bg_glass_65_ffffff_1x400.png
│ │ │ ├── ui-bg_gloss-wave_35_f6a828_500x100.png
│ │ │ ├── ui-bg_highlight-soft_100_eeeeee_1x100.png
│ │ │ ├── ui-bg_highlight-soft_75_ffe45c_1x100.png
│ │ │ ├── ui-icons_222222_256x240.png
│ │ │ ├── ui-icons_228ef1_256x240.png
│ │ │ ├── ui-icons_ef8c08_256x240.png
│ │ │ ├── ui-icons_ffd27a_256x240.png
│ │ │ └── ui-icons_ffffff_256x240.png
│ │ ├── index.html
│ │ ├── jquery-ui.css
│ │ ├── jquery-ui.js
│ │ ├── jquery-ui.min.css
│ │ ├── jquery-ui.min.js
│ │ ├── jquery-ui.structure.css
│ │ ├── jquery-ui.structure.min.css
│ │ ├── jquery-ui.theme.css
│ │ └── jquery-ui.theme.min.css
│ ├── jquery.ba-bbq.js
│ └── jquery.jsPlumb-1.3.10-all-min.js
├── messaging.ts
├── package-lock.json
├── package.json
├── pytutor.ts
├── tsconfig.json
├── typings.json
├── webpack.common.js
├── webpack.dev.js
└── webpack.prod.js
├── python-icon.png
├── pythonFiles
└── pydev
│ ├── debugger.py
│ ├── launcher.py
│ ├── pg_encoder.py
│ ├── pg_logger.py
│ └── util.py
├── src
├── commands
│ ├── index.ts
│ ├── refreshPreview.ts
│ ├── showPreview.ts
│ ├── showSource.ts
│ └── toggleLock.ts
├── common
│ ├── commandManager.ts
│ ├── dispose.ts
│ ├── file.ts
│ ├── helpers.ts
│ ├── is.ts
│ ├── lazy.ts
│ ├── logger.ts
│ ├── net
│ │ └── socket
│ │ │ └── socketStream.ts
│ └── platform
│ │ └── pathUtils.ts
├── debugger
│ ├── common
│ │ ├── contracts.ts
│ │ └── utils.ts
│ ├── debugClients
│ │ ├── baseDebugClient.ts
│ │ ├── launcherProvider.ts
│ │ └── localDebugClient.ts
│ ├── debugServers
│ │ ├── baseDebugServer.ts
│ │ └── localDebugServer.ts
│ ├── proxyCommands.ts
│ ├── pythonProcess.ts
│ └── pythonProcessCallbackHandler.ts
├── extension.ts
├── features
│ ├── preview.ts
│ ├── previewConfig.ts
│ ├── previewContentProvider.ts
│ ├── previewManager.ts
│ └── pythonOutput.ts
└── test
│ ├── common
│ └── net
│ │ └── socketStream.test.ts
│ ├── extension.test.ts
│ └── index.ts
├── tsconfig.json
├── tslint.json
└── yarn.lock
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Set default behavior to automatically normalize line endings.
2 | package.json text eol=lf
3 | package.lock.json text eol=lf
4 |
5 | preview-src/package.json text eol=lf
6 | preview-src/package-lock.json text eol=lf
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | out
2 | **/node_modules
3 | .vscode-test/
4 | *.vsix
5 |
6 | assets/index.js
7 | preview-src/node_modules
8 | preview-src/typings
9 | pythonFiles/pydev/__pycache__
10 | python-preview
--------------------------------------------------------------------------------
/.testignore:
--------------------------------------------------------------------------------
1 | .gitattributes
2 | .gitignore
3 | .testignore
4 | .vscodeignore
5 | gulpfile.js
6 | tsconfig.json
7 | tslint.json
8 | vsc-extension-quickstart.md
9 |
10 | .vscode/**
11 | .vscode
12 | .vscode-test/**
13 | .vscode-test
14 | images
15 | images/**
16 | out/test/**
17 | out/test
18 | out/**/*.map
19 | preview-src/**
20 | preview-src
21 | src/**
22 | src
23 | pythonFiles/pydev/__pycache__/**
24 | pythonFiles/pydev/__pycache__
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // See http://go.microsoft.com/fwlink/?LinkId=827846
3 | // for the documentation about the extensions.json format
4 | "recommendations": [
5 | "eg2.tslint"
6 | ]
7 | }
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | // A launch configuration that compiles the extension and then opens it inside a new window
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | {
6 | "version": "0.2.0",
7 | "configurations": [
8 | {
9 | "name": "Extension",
10 | "type": "extensionHost",
11 | "request": "launch",
12 | "runtimeExecutable": "${execPath}",
13 | "args": [
14 | "--extensionDevelopmentPath=${workspaceFolder}"
15 | ],
16 | "outFiles": [
17 | "${workspaceFolder}/out/**/*.js"
18 | ],
19 | "preLaunchTask": "npm: compile"
20 | },
21 | {
22 | "name": "Extension Tests",
23 | "type": "extensionHost",
24 | "request": "launch",
25 | "runtimeExecutable": "${execPath}",
26 | "args": [
27 | "--disable-extensions",
28 | "--extensionDevelopmentPath=${workspaceFolder}",
29 | "--extensionTestsPath=${workspaceFolder}/out/test"
30 | ],
31 | "outFiles": [
32 | "${workspaceFolder}/out/test/**/*.js"
33 | ],
34 | "preLaunchTask": "npm: compile"
35 | }
36 | ]
37 | }
38 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | // Place your settings in this file to overwrite default and user settings.
2 | {
3 | "files.exclude": {
4 | "out": false // set this to true to hide the "out" folder with the compiled JS files
5 | },
6 | "search.exclude": {
7 | "out": true // set this to false to include "out" folder in search results
8 | },
9 | // Turn off tsc task auto detection since we have the necessary tasks as npm scripts
10 | "typescript.tsc.autoDetect": "off"
11 | }
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | // See https://go.microsoft.com/fwlink/?LinkId=733558
2 | // for the documentation about the tasks.json format
3 | {
4 | "version": "2.0.0",
5 | "tasks": [
6 | {
7 | "type": "npm",
8 | "script": "watch",
9 | "problemMatcher": "$tsc-watch",
10 | "isBackground": true,
11 | "presentation": {
12 | "reveal": "never"
13 | },
14 | "group": {
15 | "kind": "build",
16 | "isDefault": true
17 | }
18 | }
19 | ]
20 | }
--------------------------------------------------------------------------------
/.vscodeignore:
--------------------------------------------------------------------------------
1 | .gitattributes
2 | .gitignore
3 | .testignore
4 | gulpfile.js
5 | tsconfig.json
6 | tslint.json
7 | vsc-extension-quickstart.md
8 | ThirdPartyNotices.txt
9 | yarn.lock
10 |
11 | .vscode/**
12 | .vscode-test/**
13 | images/**
14 | out/test/**
15 | out/**/*.map
16 | preview-src/**
17 | python-preview/**
18 | pythonFiles/pydev/__pycache__/**
19 | src/**
20 | testExtension/**
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## Version 0.0.4
2 | - Fix: Fixed cumulativeMode setting invalid error
3 |
4 | ## Version 0.0.3
5 | - Fix: Fixed style error.
6 |
7 | ## Version 0.0.2
8 | - Eliminate unnecessary contents from extension.
9 | - Add third party notices.
10 | - Add settingDemo.gif.
11 |
12 | ## Version 0.0.1
13 | - Initial release
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Dong Li
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Python Preview extension for Visual Studio Code
2 |
3 | A [Visual Studio Code](https://code.visualstudio.com/) [extension](https://marketplace.visualstudio.com/VSCode) with debugging preview support for the [Python language](https://www.python.org/).
4 |
5 |
6 | ## Features
7 |
8 | 
9 |
10 | 
11 |
12 | ## Requirements
13 |
14 | 1. Install a version of Python 3.6 or Python 2.7. make sure the location of your Python interprter is included in your PATH environment variable.
15 | 2. It's better to install [Python Extension](https://marketplace.visualstudio.com/items?itemName=ms-python.python) for Python Intellisense.
16 |
17 |
18 | ## Change Log
19 |
20 | You can checkout all our changes in our [change log](https://github.com/dongli0x00/python-preview/blob/master/CHANGELOG.md).
21 |
22 | ## Thanks
23 |
24 | Thanks to the following projects which I rely on and obtain a number of fresh new ideas from
25 | - [OnlinePythonTutor](https://github.com/pgbovine/OnlinePythonTutor)
26 | - [vscode-python](https://github.com/Microsoft/vscode-python)
27 | - [markdown-language-features](https://github.com/Microsoft/vscode/tree/master/extensions/markdown-language-features)
28 |
29 | Also special thanks to the people that have provided support, testing, etc:
30 | - [JianWei Hong](https://github.com/HongHaiyang)
31 |
32 | And finally thanks to the [Python](https://www.python.org/) development team and community and of course the awesome [vscode](https://github.com/Microsoft/vscode/graphs/contributors) team.
--------------------------------------------------------------------------------
/ThirdPartyNotices.txt:
--------------------------------------------------------------------------------
1 | pythonVisualizer
2 |
3 | THIRD-PARTY SOFTWARE NOTICES AND INFORMATION
4 | Do Not Translate or Localize
5 |
6 | This project incorporates components from the projects listed below.
7 |
8 | 1. OnlinePythonTutor (https://github.com/pgbovine/OnlinePythonTutor)
9 | 2. vscode-python (https://github.com/Microsoft/vscode-python)
10 | 3. markdown-language-features (https://github.com/Microsoft/vscode/tree/master/extensions/markdown-language-features)
11 |
12 |
13 | %% OnlinePythonTutor NOTICES AND INFORMATION BEGIN HERE
14 | ================================================================================
15 | The MIT License (MIT)
16 |
17 | Copyright (C) Philip J. Guo (philip@pgbovine.net)
18 |
19 | Permission is hereby granted, free of charge, to any person obtaining a
20 | copy of this software and associated documentation files (the
21 | "Software"), to deal in the Software without restriction, including
22 | without limitation the rights to use, copy, modify, merge, publish,
23 | distribute, sublicense, and/or sell copies of the Software, and to
24 | permit persons to whom the Software is furnished to do so, subject to
25 | the following conditions:
26 |
27 | The above copyright notice and this permission notice shall be included
28 | in all copies or substantial portions of the Software.
29 |
30 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
31 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
32 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
33 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
34 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
35 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
36 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 |
38 | ================================================================================
39 | END of OnlinePythonTutor NOTICES AND INFORMATION
40 |
41 | %% vscode-python NOTICES AND INFORMATION BEGIN HERE
42 | ================================================================================
43 | The MIT License (MIT)
44 |
45 | Copyright (c) Microsoft Corporation. All rights reserved.
46 |
47 | MIT License
48 |
49 | Permission is hereby granted, free of charge, to any person obtaining a copy
50 | of this software and associated documentation files (the "Software"), to deal
51 | in the Software without restriction, including without limitation the rights
52 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
53 | copies of the Software, and to permit persons to whom the Software is
54 | furnished to do so, subject to the following conditions:
55 |
56 | The above copyright notice and this permission notice shall be included in all
57 | copies or substantial portions of the Software.
58 |
59 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
60 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
61 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
62 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
63 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
64 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
65 | SOFTWARE.
66 |
67 | ================================================================================
68 | END of vscode-python NOTICES AND INFORMATION
69 |
70 | %% markdown-language-features
71 | ================================================================================
72 | The MIT License (MIT)
73 |
74 | MIT License
75 |
76 | Copyright (c) 2015 - present Microsoft Corporation
77 |
78 | All rights reserved.
79 |
80 | Permission is hereby granted, free of charge, to any person obtaining a copy
81 | of this software and associated documentation files (the "Software"), to deal
82 | in the Software without restriction, including without limitation the rights
83 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
84 | copies of the Software, and to permit persons to whom the Software is
85 | furnished to do so, subject to the following conditions:
86 |
87 | The above copyright notice and this permission notice shall be included in all
88 | copies or substantial portions of the Software.
89 |
90 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
91 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
92 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
93 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
94 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
95 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
96 | SOFTWARE.
97 |
98 | ================================================================================
99 | END of markdown-language-features NOTICES AND INFORMATION
--------------------------------------------------------------------------------
/assets/Preview.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/assets/PreviewOnRightPane_16x.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/assets/PreviewOnRightPane_16x_dark.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/assets/Preview_inverse.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/assets/ViewSource.svg:
--------------------------------------------------------------------------------
1 |
3 | ]>
--------------------------------------------------------------------------------
/assets/ViewSource_inverse.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/assets/images/ui-bg_diagonals-thick_18_b81900_40x40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongli0x00/python-preview/f574a46aad9a0483fcfd1ad331405cce6e15b8d9/assets/images/ui-bg_diagonals-thick_18_b81900_40x40.png
--------------------------------------------------------------------------------
/assets/images/ui-bg_diagonals-thick_20_666666_40x40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongli0x00/python-preview/f574a46aad9a0483fcfd1ad331405cce6e15b8d9/assets/images/ui-bg_diagonals-thick_20_666666_40x40.png
--------------------------------------------------------------------------------
/assets/images/ui-bg_flat_10_000000_40x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongli0x00/python-preview/f574a46aad9a0483fcfd1ad331405cce6e15b8d9/assets/images/ui-bg_flat_10_000000_40x100.png
--------------------------------------------------------------------------------
/assets/images/ui-bg_glass_100_f6f6f6_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongli0x00/python-preview/f574a46aad9a0483fcfd1ad331405cce6e15b8d9/assets/images/ui-bg_glass_100_f6f6f6_1x400.png
--------------------------------------------------------------------------------
/assets/images/ui-bg_glass_100_fdf5ce_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongli0x00/python-preview/f574a46aad9a0483fcfd1ad331405cce6e15b8d9/assets/images/ui-bg_glass_100_fdf5ce_1x400.png
--------------------------------------------------------------------------------
/assets/images/ui-bg_glass_65_ffffff_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongli0x00/python-preview/f574a46aad9a0483fcfd1ad331405cce6e15b8d9/assets/images/ui-bg_glass_65_ffffff_1x400.png
--------------------------------------------------------------------------------
/assets/images/ui-bg_gloss-wave_35_f6a828_500x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongli0x00/python-preview/f574a46aad9a0483fcfd1ad331405cce6e15b8d9/assets/images/ui-bg_gloss-wave_35_f6a828_500x100.png
--------------------------------------------------------------------------------
/assets/images/ui-bg_highlight-soft_100_eeeeee_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongli0x00/python-preview/f574a46aad9a0483fcfd1ad331405cce6e15b8d9/assets/images/ui-bg_highlight-soft_100_eeeeee_1x100.png
--------------------------------------------------------------------------------
/assets/images/ui-bg_highlight-soft_75_ffe45c_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongli0x00/python-preview/f574a46aad9a0483fcfd1ad331405cce6e15b8d9/assets/images/ui-bg_highlight-soft_75_ffe45c_1x100.png
--------------------------------------------------------------------------------
/assets/images/ui-icons_222222_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongli0x00/python-preview/f574a46aad9a0483fcfd1ad331405cce6e15b8d9/assets/images/ui-icons_222222_256x240.png
--------------------------------------------------------------------------------
/assets/images/ui-icons_228ef1_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongli0x00/python-preview/f574a46aad9a0483fcfd1ad331405cce6e15b8d9/assets/images/ui-icons_228ef1_256x240.png
--------------------------------------------------------------------------------
/assets/images/ui-icons_ef8c08_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongli0x00/python-preview/f574a46aad9a0483fcfd1ad331405cce6e15b8d9/assets/images/ui-icons_ef8c08_256x240.png
--------------------------------------------------------------------------------
/assets/images/ui-icons_ffd27a_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongli0x00/python-preview/f574a46aad9a0483fcfd1ad331405cce6e15b8d9/assets/images/ui-icons_ffd27a_256x240.png
--------------------------------------------------------------------------------
/assets/images/ui-icons_ffffff_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongli0x00/python-preview/f574a46aad9a0483fcfd1ad331405cce6e15b8d9/assets/images/ui-icons_ffffff_256x240.png
--------------------------------------------------------------------------------
/assets/pytutor.common.css:
--------------------------------------------------------------------------------
1 | /* ==========================================================================
2 | Pytutor通用样式定义
3 | ========================================================================== */
4 |
5 | body {
6 | font-family: "Segoe WPC", "Segoe UI", "SFUIText-Light", "HelveticaNeue-Light", sans-serif, "Droid Sans Fallback";
7 | font-size: 16px;
8 | margin-left: auto;
9 | margin-right: auto;
10 | }
11 |
12 | div.ExecutionVisualizer table.visualizer td.vizLayoutTd {
13 | vertical-align: top
14 | }
15 |
16 | /* ==========================================================================
17 | Visualizer左边栏样式定义
18 | ========================================================================== */
19 |
20 | /**
21 | * 语言标题。
22 | */
23 | div.ExecutionVisualizer div#langDisplayDiv {
24 | margin-top: 2pt;
25 | margin-bottom: 3pt;
26 | text-align: center;
27 | font-size: 14pt;
28 | }
29 |
30 | /**
31 | * 代码外框。
32 | */
33 | div.ExecutionVisualizer div#pyCodeOutputDiv {
34 | max-height: 460px;
35 | overflow: auto;
36 | margin-left: auto;
37 | margin-right: auto;
38 | }
39 |
40 | /**
41 | * 代码内框。
42 | */
43 | div.ExecutionVisualizer table#pyCodeOutput {
44 | /* 代码居中 */
45 | margin: 6px auto;
46 | border-top: 1px solid;
47 | border-bottom: 1px solid;
48 | padding-top: 3px;
49 | border-spacing: 0px;
50 | border-collapse: separate;
51 | font-family: Consolas;
52 | font-size: 11pt;
53 | line-height: 1.1em;
54 | }
55 |
56 | /**
57 | * 代码所在行。
58 | */
59 | div.ExecutionVisualizer table#pyCodeOutput td {
60 | white-space: nowrap;
61 | vertical-align: middle;
62 | }
63 |
64 | /**
65 | * 代码内框左沟槽。
66 | */
67 | div.ExecutionVisualizer #leftCodeGutterSVG {
68 | width: 18px;
69 | min-width: 18px;
70 | height: 0px;
71 | }
72 |
73 | /**
74 | * 代码执行箭头。
75 | */
76 | div.ExecutionVisualizer #prevLegendArrowSVG,
77 | div.ExecutionVisualizer #curLegendArrowSVG {
78 | width: 18px;
79 | height: 10px;
80 | }
81 |
82 | /**
83 | * 代码行号。
84 | */
85 | div.ExecutionVisualizer table#pyCodeOutput .lineNo {
86 | padding: 0.2em 0.5em 0.2em 0.3em;
87 | text-align: right;
88 | }
89 |
90 | /**
91 | * 代码。
92 | */
93 | div.ExecutionVisualizer table#pyCodeOutput .cod {
94 | margin-left: 3px;
95 | padding-left: 7px;
96 | text-align: left;
97 | }
98 |
99 | /**
100 | 图例,用来说明箭头含义。
101 | */
102 | div.ExecutionVisualizer div#legendDiv {
103 | padding: 0px;
104 | text-align: left;
105 | font-size: 9pt;
106 | }
107 |
108 | /**
109 | * 用来说明Visualier用法。
110 | */
111 | div.ExecutionVisualizer #codeFooterDocs {
112 | margin-top: 5px;
113 | margin-bottom: 12px;
114 | width: 95%;
115 | font-size: 8pt;
116 | }
117 |
118 | /**
119 | * 代码执行进度条标题。
120 | */
121 | div.ExecutionVisualizer #executionSliderCaption {
122 | margin-top: 15px;
123 | font-size: 8pt;
124 | }
125 |
126 | /**
127 | * 代码执行进度条。
128 | */
129 | div.ExecutionVisualizer #executionSlider {
130 | margin-top: 15px;
131 | margin-bottom: 5px;
132 | width: 98%;
133 | }
134 |
135 | /**
136 | * 滑杆以及滑杆手柄。
137 | * 此处指进度条和进度条当前进度点。
138 | */
139 | div.ExecutionVisualizer .ui-slider .ui-slider-handle {
140 | border: 1px solid;
141 | }
142 |
143 | /**
144 | * 代码执行进度条底部,用来显示断点信息。
145 | */
146 | div.ExecutionVisualizer #executionSliderFooter {
147 | margin-top: -7px;
148 | }
149 |
150 | /**
151 | * 调试控件。
152 | */
153 | div.ExecutionVisualizer #vcrControls {
154 | margin: 15px auto;
155 | text-align: center;
156 | }
157 |
158 | /**
159 | * 调试按钮。
160 | */
161 | div.ExecutionVisualizer #vcrControls button {
162 | margin-left: 2px;
163 | margin-right: 2px;
164 | border: 1px solid;
165 | border-radius: 28px;
166 | cursor: pointer;
167 | }
168 |
169 | /**
170 | * 代码执行当前所处位置。
171 | */
172 | div.ExecutionVisualizer #vcrControls #curInstr {
173 | margin-left: 4px;
174 | margin-right: 4px;
175 | }
176 |
177 | /**
178 | * 用户输入窗口。
179 | */
180 | div.ExecutionVisualizer div#rawUserInputDiv {
181 | margin: 5px auto;
182 | border: 1px solid;
183 | padding: 5px;
184 | width: 95%;
185 | text-align: center;
186 | }
187 |
188 | /**
189 | * 错误信息输出窗口。
190 | */
191 | div.ExecutionVisualier #errorOutput {
192 | margin-bottom: 4px;
193 | padding-top: 2px;
194 | font-size: 11pt;
195 | line-height: 1.5em;
196 | }
197 |
198 | /**
199 | * 调整大小的分隔符。
200 | */
201 | .ui-resizable-e {
202 | border: 3px solid;
203 | width: 1px;
204 | }
205 |
206 | .ui-resizable-s {
207 | border: 3px solid;
208 | height: 1px;
209 | }
210 |
211 | /* ==========================================================================
212 | Visualizer右边栏样式定义
213 | ========================================================================== */
214 |
215 | /**
216 | * 程序控制台输出窗口。
217 | */
218 | div.ExecutionVisualizer div#progOutputs {
219 | margin-left: 13px;
220 | margin-bottom: 3px;
221 | }
222 |
223 | /**
224 | * 程序控制台窗口说明。
225 | */
226 | div.ExecutionVisualizer #printOutputDocs {
227 | margin-bottom: 3px;
228 | font-size: 8pt;
229 | }
230 |
231 | /**
232 | * 程序标准输出。
233 | */
234 | div.ExecutionVisualizer #pyStdout {
235 | border: 1px solid;
236 | padding: 3px;
237 | overflow: auto;
238 | resize: none;
239 | font-family: Consolas;
240 | font-size: 10pt;
241 | }
242 |
243 | /**
244 | * 栈和堆的样式定义。
245 | */
246 | div.ExecutionVisualizer td#stack_td,
247 | div.ExecutionVisualizer td#heap_td {
248 | vertical-align: top;
249 | font-family: Consolas;
250 | font-size: 12pt;
251 | }
252 |
253 | /**
254 | * 全局变量区域和栈。
255 | */
256 | div.ExecutionVisualizer div#globals_area,
257 | div.ExecutionVisualizer div#stack {
258 | padding-left: 10px;
259 | padding-right: 30px;
260 | }
261 |
262 | /**
263 | * 栈标题。
264 | */
265 | div.ExecutionVisualizer div#stackHeader {
266 | margin-bottom: 15px;
267 | text-align: right;
268 | font-size: 14pt;
269 | }
270 |
271 | /**
272 | * 栈帧。
273 | */
274 | div.ExecutionVisualizer div.stackFrame,
275 | div.ExecutionVisualizer div.zombieStackFrame {
276 | margin-bottom: 15px;
277 | padding: 2px 6px 4px;
278 | }
279 |
280 | div.ExecutionVisualizer div.stackFrame {
281 | border-left: 1px solid;
282 | }
283 |
284 | div.ExecutionVisualizer div.zombieStackFrame {
285 | border-left: 1px dotted;
286 | opacity: 0.5;
287 | }
288 |
289 | /**
290 | * 栈帧标题。
291 | */
292 | div.ExecutionVisualizer div.stackFrameHeader {
293 | margin-top: 4px;
294 | margin-bottom: 3px;
295 | white-space: nowrap;
296 | font-family: Consolas;
297 | font-style: italic;
298 | font-size: 12pt;
299 | }
300 |
301 | /**
302 | * 栈帧中变量与变量值的表格。
303 | */
304 | div.ExecutionVisualizer .stackFrameVarTable {
305 | /* 右对齐 */
306 | margin-left: auto;
307 | margin-right: 0px;
308 | padding-left: 3px;
309 | border-collapse: separate;
310 | border-spacing: 2px;
311 | text-align: right;
312 | }
313 |
314 | /**
315 | * 栈帧中的变量。
316 | */
317 | div.ExecutionVisualizer td.stackFrameVar {
318 | padding: 3px 8px 3px 1px;
319 | text-align: right;
320 | }
321 |
322 | /**
323 | * 栈帧中的变量值。
324 | */
325 | div.ExecutionVisualizer td.stackFrameValue {
326 | border-bottom: 1px solid;
327 | border-left: 1px solid;
328 | padding: 3px 1px 3px 3px;
329 | vertical-align: middle;
330 | text-align: left;
331 | }
332 |
333 | /**
334 | * 栈帧中返回值。
335 | */
336 | div.ExecutionVisualizer .retval {
337 | font-size: 8pt;
338 | }
339 |
340 | /**
341 | * 堆。
342 | */
343 | div.ExecutionVisualizer div#heap {
344 | float: left;
345 | padding-left: 30px;
346 | }
347 |
348 | /**
349 | * 堆标题。
350 | */
351 | div.ExecutionVisualizer div#heapHeader {
352 | margin-bottom: 15px;
353 | font-size: 14pt;
354 | }
355 |
356 | /**
357 | * 堆对象外框。
358 | */
359 | div.ExecutionVisualizer table.heapRow {
360 | margin-bottom: 10px;
361 | }
362 |
363 | /**
364 | * 堆对象内框。
365 | */
366 | div.ExecutionVisualizer td.toplevelHeapObject {
367 | padding: 4px 8px;
368 | }
369 |
370 | /**
371 | * 堆对象。
372 | */
373 | div.ExecutionVisualizer div.heapObject {
374 | padding-left: 2px;
375 | }
376 |
377 | /**
378 | * 类型标签。
379 | */
380 | div.ExecutionVisualizer .objectIdLabel,
381 | div.ExecutionVisualizer .typeLabel {
382 | margin-bottom: 2px;
383 | font-size: 8pt;
384 | }
385 |
386 | /**
387 | * 堆中原始类型,比如int类型。
388 | */
389 | div.ExecutionVisualizer div.heapPrimitive {
390 | padding-left: 4px;
391 | }
392 |
393 | /**
394 | * 原始类型的渲染。
395 | */
396 | div.ExecutionVisualizer .stringObj,
397 | div.ExecutionVisualizer .customObj,
398 | div.ExecutionVisualizer .funcObj {
399 | white-space: nowrap;
400 | }
401 |
402 | /* ==========================================================================
403 | 基本复合类型的渲染
404 | ========================================================================== */
405 |
406 | /**
407 | * list、tuple和set类型。
408 | */
409 | div.ExecutionVisualizer table.listTbl {
410 | border: 0px solid;
411 | border-spacing: 0px;
412 | }
413 |
414 | div.ExecutionVisualizer table.tupleTbl {
415 | border-width: 1px 1px 1px 0px;
416 | border-style: solid;
417 | border-spacing: 0px;
418 | }
419 |
420 | div.ExecutionVisualizer table.setTbl {
421 | border: 1px solid;
422 | border-spacing: 0px;
423 | text-align: center;
424 | }
425 |
426 | /**
427 | * list和tuple头。
428 | */
429 | div.ExecutionVisualizer table.listTbl td.listHeader,
430 | div.ExecutionVisualizer table.tupleTbl td.tupleHeader {
431 | border-left: 1px solid;
432 | padding: 2px 1px 3px 4px;
433 | text-align: left;
434 | font-size: 8pt;
435 | }
436 |
437 |
438 | /**
439 | * list、tuple和set中的元素。
440 | */
441 | div.ExecutionVisualizer table.listTbl td.listElt {
442 | border-bottom: 1px solid;
443 | border-left: 1px solid;
444 | }
445 |
446 | div.ExecutionVisualizer table.tupleTbl td.tupleElt {
447 | border-left: 1px solid;
448 | }
449 |
450 | div.ExecutionVisualizer table.listTbl td.listElt,
451 | div.ExecutionVisualizer table.tupleTbl td.tupleElt {
452 | padding: 0px 10px 8px;
453 | vertical-align: bottom;
454 | }
455 |
456 | div.ExecutionVisualizer table.setTbl td.setElt {
457 | padding: 8px
458 | }
459 |
460 | /**
461 | * 自定义对象。
462 | */
463 | div.ExecutionVisualizer tabl.customObjTbl {
464 | border: 1px solid;
465 | }
466 |
467 | /**
468 | * 自定义对象中的元素。
469 | */
470 | div.ExecutionVisualizer table.customObjTbl td.customObjElt {
471 | padding: 5px;
472 | }
473 |
474 | /**
475 | * dict、instance、class。
476 | */
477 | div.ExecutionVisualizer table.dictTbl,
478 | div.ExecutionVisualizer table.instTbl,
479 | div.ExecutionVisualizer table.classTbl {
480 | border-spacing: 1px;
481 | }
482 |
483 | /**
484 | * dict、instance和class中的键。
485 | */
486 | div.ExecutionVisualizer table.dictTbl td.dictKey,
487 | div.ExecutionVisualizer table.dictTbl td.instKey,
488 | div.ExecutionVisualizer table.classTbl td.classKey {
489 | padding: 6px 4px 6px 10px;
490 | text-align: right;
491 | }
492 |
493 | /**
494 | * dict、instance和class中的值。
495 | */
496 | div.ExecutionVisualizer table.dictTbl td.dictVal,
497 | div.ExecutionVisualizer table.instTbl td.instVal,
498 | div.ExecutionVisualizer table.classTbl td.classVal {
499 | padding: 6px 10px 6px 4px;
500 | }
501 |
502 | /**
503 | * class和function。
504 | */
505 | div.ExecutionVisualizer table.classTbl,
506 | div.ExecutionVisualizer table.funcTbl {
507 | border-collapse: collapse;
508 | border: 1px solid;
509 | }
510 |
511 | /**
512 | * class和instance表格下的元素。
513 | */
514 | div.ExecutionVisualizer table.classTbl td,
515 | div.ExectuonVisualizer tabl.instTbl td {
516 | border-bottom: 1px solid;
517 | }
518 |
519 | /**
520 | * class和instance中的值。
521 | */
522 | div.ExecutionVisualizer table.classTbl td.classVal,
523 | div.ExecutionVisualizer table.instTbl td.instVal {
524 | border-left: 1px solid;
525 | }
526 |
527 | /**
528 | * dict嵌入到list、tuple、dict、inst以及class中的样式。
529 | */
530 | div.ExecutionVisualizer td.listElt table.dictTbl,
531 | div.ExecutionVisualizer td.tupleElt table.dictTbl,
532 | div.ExecutionVisualizer td.dictVal table.dictTbl,
533 | div.ExecutionVisualizer td.instVal table.dictTbl,
534 | div.ExecutionVisualizer td.classVal table.dictTbl {
535 | border: 1px solid;
536 | }
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 | const cp = require('child_process');
4 | const gulp = require('gulp');
5 | const del = require('del');
6 | const filter = require('gulp-filter');
7 | const parseSemver = require('parse-semver');
8 | const _ = require('underscore');
9 |
10 | function asYarnDependency(prefix, tree) {
11 | let parseResult;
12 |
13 | try {
14 | parseResult = parseSemver(tree.name);
15 | } catch (err) {
16 | err.message += `: ${tree.name}`;
17 | console.warn(`Could not parse semver: ${tree.name}`);
18 | return null;
19 | }
20 |
21 | if (parseResult.version !== parseResult.range) {
22 | return null;
23 | }
24 |
25 | const name = parseResult.name;
26 | const version = parseResult.version;
27 | const dependencyPath = path.join(prefix, name);
28 | const children = [];
29 |
30 | for (const child of (tree.children || [])) {
31 | const dep = asYarnDependency(path.join(prefix, name, 'node_modules'), child);
32 |
33 | if (dep) {
34 | children.push(dep);
35 | }
36 | }
37 |
38 | return { name, version, path: dependencyPath, children };
39 | }
40 |
41 | function getYarnProductionDependencies(cwd) {
42 | const raw = cp.execSync(`yarn list --json`, { cwd, encoding: 'utf8', env: { ...process.env, NODE_ENV: 'production' }, stdio: [null, null, 'ignore'] });
43 | const match = /^{"type":"tree".*$/m.exec(raw);
44 |
45 | if (!match || match.length !== 1) {
46 | throw new Error('Could not parse result of `yarn lst --json`');
47 | }
48 |
49 | const trees = JSON.parse(match[0]).data.trees;
50 |
51 | return trees.map(tree => asYarnDependency(path.join(cwd, 'node_modules'), tree))
52 | .filter(dep => !!dep);
53 | }
54 |
55 | function getProductionDependencies(cwd) {
56 | const result = [];
57 | const deps = getYarnProductionDependencies(cwd);
58 | const flatten = dep => { result.push({ name: dep.name, version: dep.version, path: dep.path }); dep.children.forEach(flatten) };
59 | deps.forEach(flatten);
60 |
61 | return _.uniq(result);
62 | }
63 |
64 | gulp.task('printDeps', () => {
65 | const dependencies = getProductionDependencies(__dirname);
66 | dependencies.map(dep => dep.path).forEach(path => console.log(path));
67 | });
68 |
69 | gulp.task('clean:python-preview', () => {
70 | return del(['python-preview'])
71 | });
72 |
73 | gulp.task('extract:python-preview', ['clean:python-preview'], () => {
74 | const pythonPreviewIgnore = fs.readFileSync('./.testignore', 'utf-8')
75 | .split('\n')
76 | .map(line => line.trim())
77 | .filter(line => line !== '')
78 | .map(line => '!' + line);
79 | const pythonPreviewFilter = filter(['**', '!node_modules/**', '!node_modules', ...pythonPreviewIgnore]);
80 | gulp.src('./**', {base: '.'})
81 | .pipe(pythonPreviewFilter)
82 | .pipe(gulp.dest('python-preview'));
83 |
84 | const dependencies = getProductionDependencies(__dirname);
85 | const paths = dependencies.map(dep => path.join(dep.path, '**'));
86 | return gulp.src(paths, { base: './node_modules' })
87 | .pipe(gulp.dest('./python-preview/node_modules'));
88 | });
--------------------------------------------------------------------------------
/images/previewDemo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongli0x00/python-preview/f574a46aad9a0483fcfd1ad331405cce6e15b8d9/images/previewDemo.gif
--------------------------------------------------------------------------------
/images/settingDemo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongli0x00/python-preview/f574a46aad9a0483fcfd1ad331405cce6e15b8d9/images/settingDemo.gif
--------------------------------------------------------------------------------
/package.nls.json:
--------------------------------------------------------------------------------
1 | {
2 | "displayName": "Python Preview",
3 | "description": "Provide Preview for Python Execution.",
4 | "pythonPreview.showPreview.title": "Open Preview",
5 | "pythonPreview.showPreviewToSide.title": "Open Preview to the Side",
6 | "pythonPreview.showLockedPreviewToSide.title": "Open Locked Preview to the Side",
7 | "pythonPreview.showSource.title": "Show Source",
8 | "pythonPreview.refresh.title": "Refresh Preview",
9 | "pythonPreview.toggleLock.title": "Toggle Preview Locking",
10 | "pythonPreview.disableHeapNesting.desc": "Set how heap objects should be rendered. \"true\" render all heap objects at the top level. Otherwise, nest heap objects.",
11 | "pythonPreview.textualMemoryLabels.desc": "Render refrences using textual memory labels rather than as jsPlumb arrows.",
12 | "pythonPreview.compactFuncLabels.desc": "Render functions with a 'func' prefix and not type label.",
13 | "pythonPreview.showAllFrameLabels.desc": "Display frame and parent frame labels for all functions.",
14 | "pythonPreview.hideCode.desc": "Hide the code display.",
15 | "pythonPreview.codAndNavWidth.desc": "Set code and navigation area width.",
16 | "pythonPreview.allowAllModules.desc": "Set whether all modules can be imported.",
17 | "pythonPreview.maxExecutedLines.desc": "Set the max number of executed lines, in order to against infinite loops.",
18 | "pythonPreview.cumulativeMode.desc": "Display all stack frames that have ever exited rather than only currently on the stack.",
19 | "pythonPreview.trace.desc": "Enable debug logging for the python-preview extension.",
20 |
21 | "pythonPreview.fontFamily.desc": "Control the font family used in the python preview.",
22 | "pythonPreview.fontSize.desc": "Control the font size in pixels used in the python preview.",
23 | "pythonPreview.langDisplay.fontFamily.desc": "Control the font family used in the lang display area.",
24 | "pythonPreview.langDisplay.fontSize.desc": "Control the font size in pixels used in the lang display area.",
25 | "pythonPreview.code.fontFamily.desc": "Control the font family used in the code display area.",
26 | "pythonPreview.code.fontSize.desc": "Control the font size in pixels in the code display area.",
27 | "pythonPreview.code.lineHeight.desc": "Control the line height used in the code.",
28 | "pythonPreview.legend.fontFamily.desc": "Control the font family used in the arrow legend.",
29 | "pythonPreview.legend.fontSize.desc": "Control the font size in pixels used in the arrow legend.",
30 | "pythonPreview.codeFooterDocs.fontFamily.desc": "Control the font family used in the code footer docs.",
31 | "pythonPreview.codeFooterDocs.fontSize.desc": "Control the font size in pixels used in the code footer docs.",
32 | "pythonPreview.printOutputDocs.fontFamily.desc": "Control the font family used int the print output docs.",
33 | "pythonPreview.printOutputDocs.fontSize.desc": "Control the font size in pixels in the print output docs.",
34 | "pythonPreview.pyStdout.fontSize.desc": "Control the font size in pixels used in the python stdout window.",
35 | "pythonPreview.pyStdout.fontFamily.desc": "Control the font family used in the python stdout window.",
36 | "pythonPreview.stackAndHeapHeader.fontFamily.desc": "Control the font family used in the stack header and heap header.",
37 | "pythonPreview.stackAndHeapHeader.fontSize.desc": "Control the font size in pixels used in the stack header and heap header.",
38 | "pythonPreview.stackFrame.fontFamily.desc": "Control the font family used in the stack frame.",
39 | "pythonPreview.stackFrame.fontSize.desc": "Control the font size in pixels used in the stack frame.",
40 | "pythonPreview.retVal.fontSize.desc": "Control the font size in pixels used in the function return value.",
41 | "pythonPreview.stackFrameHeader.fontFamily.desc": "Control the font family used in the stack frame header.",
42 | "pythonPreview.stackFrameHeader.fontSize.desc": "Control the font size in pixels used in the stack frame header.",
43 | "pythonPreview.heapObject.fontFamily.desc": "Control the font family used in the heap object.",
44 | "pythonPreview.heapObject.fontSize.desc": "Control the font size in pixels used in the heap object.",
45 | "pythonPreview.typeLabel.fontFamily.desc": "Control the font family used in the type label of heap object.",
46 | "pythonPreview.typeLabel.fontSize.desc": "Control the font size in pixels used in the type label of heap object.",
47 |
48 | "pythonPreview.light.highlightedArrow.color.desc": "Control the color used in highlighted arrow in vscode light theme.",
49 | "pythonPreview.light.highlightedStackFrame.bgColor.desc": "Control the background color used in highlighted stack frame in vscode light theme.",
50 | "pythonPreview.light.list-tuple-setTbl.bgColor.desc": "Control the background color used in list, tuple and set in vscode light theme.",
51 | "pythonPreview.light.dict-class-instKey.bgColor.desc": "Control the background color used in dict, class and instance key in vscode light theme.",
52 | "pythonPreview.light.dict-class-instVal.bgColor.desc": "Control the background color used in dict, class and instance value in vscode light theme.",
53 | "pythonPreview.dark.highlightedArrow.color.desc": "Control the color used in highlighted arrow in vscode dark theme.",
54 | "pythonPreview.dark.highlightedStackFrame.bgColor.desc": "Control the background color used in highlighted stack frame in vscode dark theme.",
55 | "pythonPreview.dark.list-tuple-setTbl.bgColor.desc": "Control the background color used in list, tuple and set in vscode dark theme.",
56 | "pythonPreview.dark.dict-class-instKey.bgColor.desc": "Control the background color used in dict, class and instance key in vscode dark theme.",
57 | "pythonPreview.dark.dict-class-instVal.bgColor.desc": "Control the background color used in dict, class and instance value in vscode dark theme.",
58 | "pythonPreview.high-contrast.highlightedArrow.color.desc": "Control the color used in highlighted stack frame in vscode high-contrast theme.",
59 | "pythonPreview.high-contrast.highlightedStackFrame.bgColor.desc": "Control the background color used in highlighted stack frame in vscode high-contrast theme.",
60 | "pythonPreview.high-contrast.list-tuple-setTbl.bgColor.desc": "Control the background color used in list, tuple and set in vscode high-contrast theme.",
61 | "pythonPreview.high-contrast.dict-class-instKey.bgColor.desc": "Control the background color used in dict, class and instance key in vscode high-contrast theme.",
62 | "pythonPreview.high-contrast.dict-class-instVal.bgColor.desc": "Control the background color used in dict, class and instance value in vscode high-contrast theme."
63 | }
--------------------------------------------------------------------------------
/package.nls.zh-cn.json:
--------------------------------------------------------------------------------
1 | {
2 | "displayName": "Python 预览",
3 | "description": "为 Python 执行提供预览效果。",
4 | "pythonPreview.showPreview.title": "打开预览",
5 | "pythonPreview.showPreviewToSide.title": "在侧边打开预览",
6 | "pythonPreview.showLockedPreviewToSide.title": "在侧边打开锁定的预览",
7 | "pythonPreview.showSource.title": "显示源",
8 | "pythonPreview.refresh.title": "刷新预览",
9 | "pythonPreview.toggleLock.title": "切换预览的锁定状态",
10 | "pythonPreview.disableHeapNesting.desc": "设置堆对象的渲染方式。\"true\" 在顶层渲染所有的堆对象。否则, 嵌套堆对象。",
11 | "pythonPreview.textualMemoryLabels.desc": "使用文本内存标签而不是jsPlumb箭头渲染引用。",
12 | "pythonPreview.compactFuncLabels.desc": "使用 \"func\" 前缀渲染函数类型标签。",
13 | "pythonPreview.showAllFrameLabels.desc": "显示所有函数的栈帧以及父栈帧标签。",
14 | "pythonPreview.hideCode.desc": "隐藏代码显示。",
15 | "pythonPreview.codAndNavWidth": "设置代码和导航区域宽度。",
16 | "pythonPreview.allowAllModules.desc": "设置是否可以导入所有模块。",
17 | "pythonPreview.maxExecutedLines.desc": "设置执行行数的最大值,以防无限的循环。",
18 | "pythonPreview.cumulativeMode.desc": "显示所有已退出的栈帧,而不仅是当前栈帧。",
19 | "pythonPreview.trace.desc": "对 python-preview 启用调试日志记录。",
20 |
21 | "pythonPreview.fontFamily.desc": "控制 python 预览中使用的字体系列。",
22 | "pythonPreview.fontSize.desc": "控制 python 预览中使用的字号(以像素为单位)。",
23 | "pythonPreview.langDisplay.fontFamily.desc": "控制语言显示区域中使用的字体系列。",
24 | "pythonPreview.langDisplay.fontSize.desc": "控制语言显示区域中使用的字号(以像素为单位)。",
25 | "pythonPreview.code.fontFamily.desc": "控制代码显示区域中使用的字体系列。",
26 | "pythonPreview.code.fontSize.desc": "控制代码显示区域中使用的字号(以像素为单位)。",
27 | "pythonPreview.code.lineHeight.desc": "控制代码显示区域中使用的行高。",
28 | "pythonPreview.legend.fontFamily.desc": "控制箭头图例中使用的字体系列。",
29 | "pythonPreview.legend.fontSize.desc": "控制箭头图例中使用的字号(以像素为单位)。",
30 | "pythonPreview.codeFooterDocs.fontFamily.desc": "控制代码页脚文档中使用的字体系列。",
31 | "pythonPreview.codeFooterDocs.fontSize.desc": "控制代码页脚文档中使用的字号(以像素为单位)。",
32 | "pythonPreview.printOutputDocs.fontFamily.desc": "控制打印输出文档中使用的字体系列。",
33 | "pythonPreview.printOutoutDocs.fontSize.desc": "控制打印输出文档中使用的字号(以像素為单位)。",
34 | "pythonPreview.pyStdout.fontFamily.desc": "控制 python 标准输出窗口中使用的字体系列。",
35 | "pythonPreview.pyStdout.fontSize.desc": "控制 python 标准输出窗口中使用的字号(以像素为单位)。",
36 | "pythonPreview.stackAndHeapHeader.fontFamily.desc": "控制栈头部和堆头部中使用的字体系列。",
37 | "pythonPreview.stackAndHeapHeader.fontSize.desc": "控制栈头部和堆头部中使用的字号(以像素为单位)。",
38 | "pythonPreview.stackFrame.fontFamily.desc": "控制栈帧中使用的字体系列。",
39 | "pythonPreview.stackFrame.fontSize.desc": "控制栈帧中使用的字号(以像素为单位)。",
40 | "pythonPreview.retVal.fontSize.desc": "控制函数返回值中使用的字号(以像素为单位)。",
41 | "pythonPreview.stackFrameHeader.fontFamily.desc": "控制栈帧头部中使用的字体系列。",
42 | "pythonPreview.stackFrameHeader.fontSize.desc": "控制栈帧头部中使用的字号(以像素为单位)。",
43 | "pythonPreview.heapObject.fontFamily.desc": "控制堆对象中使用的字体系列。",
44 | "pythonPreview.heapObject.fontSize.desc": "控制堆对象中使用的字号(以像素为单位)。",
45 | "pythonPreview.typeLabel.fontFamily.desc": "控制堆对象的类型标签中使用的字体系列。",
46 | "pythonPreview.typeLabel.fontSize.desc": "控制堆对象的类型标签中使用的字号(以像素为单位)。",
47 |
48 | "pythonPreview.light.highlightedArrow.color.desc": "控制 vscode 浅色主题下高亮箭头中使用的颜色。",
49 | "pythonPreview.light.highlightedStackFrame.bgColor.desc": "控制 vscode 浅色主题中高亮堆栈使用的背景色。",
50 | "pythonPreview.light.list-tuple-setTbl.bgColor.desc": "控制 vscode 浅色主题下列表、元祖和集合使用的背景色。",
51 | "pythonPreview.light.dict-class-instKey.bgColor.desc": "控制 vscode 浅色主题下字典、类和实例中键使用的背景色。",
52 | "pythonPreview.light.dict-class-instVal.bgColor.desc": "控制 vscode 浅色主题下字典、类和实例中值使用的背景色。",
53 | "pythonPreview.dark.highlightedArrow.color.desc": "控制 vscode 深色主题下高亮箭头中使用的颜色。",
54 | "pythonPreview.dark.highlightedStackFrame.bgColor.desc": "控制 vscode 深色主题中高亮堆栈使用的背景色。",
55 | "pythonPreview.dark.list-tuple-setTbl.bgColor.desc": "控制 vscode 深色主题下列表、元祖和集合使用的背景色。",
56 | "pythonPreview.dark.dict-class-instKey.bgColor.desc": "控制 vscode 深色主题下字典、类和实例中键使用的背景色。",
57 | "pythonPreview.dark.dict-class-instVal.bgColor.desc": "控制 vscode 深色主题下字典、类和实例中值使用的背景色。",
58 | "pythonPreview.high-contrast.highlightedArrow.color.desc": "控制 vscode 高对比度主题下高亮箭头中使用的颜色。",
59 | "pythonPreview.high-contrast.highlightedStackFrame.bgColor.desc": "控制 vscode 高对比度主题中高亮堆栈使用的背景色。",
60 | "pythonPreview.high-contrast.list-tuple-setTbl.bgColor.desc": "控制 vscode 高对比度主题下列表、元祖和集合使用的背景色。",
61 | "pythonPreview.high-contrast.dict-class-instKey.bgColor.desc": "控制 vscode 高对比度主题下字典、类和实例中键使用的背景色。",
62 | "pythonPreview.high-contrast.dict-class-instVal.bgColor.desc": "控制 vscode 高对比度主题下字典、类和实例中值使用的背景色。"
63 | }
--------------------------------------------------------------------------------
/package.nls.zh-tw.json:
--------------------------------------------------------------------------------
1 | {
2 | "displayName": "Python 預覽",
3 | "description": "为 Python 執行提供預覽效果。",
4 | "pythonPreview.showPreview.title": "打開預覽。",
5 | "pythonPreview.showPreviewToSide.title": "在側邊打開預覽",
6 | "pythonPreview.showLockedPreviewToSide.title": "在側邊打開鎖定的預覽",
7 | "pythonPreview.showSource.title": "顯示源",
8 | "pythonPreview.refresh.title": "刷新預覽",
9 | "pythonPreview.toggleLock.title": "切換預覽的鎖定狀態",
10 | "pythonPreview.disableHeapNesting.desc": "設置堆對象的渲染方式。\"true\" 在頂層渲染所有的堆對象。否則,嵌套對對象。",
11 | "pythonPreview.textualMemoryLabels.desc": "使用文本內存標籤而不是jsPlumb箭頭渲染引用。",
12 | "pythonPreview.compactFuncLabels.desc": "使用 \"func\" 前綴渲染函數類型標籤。",
13 | "pythonPreview.showAllFrameLabels.desc": "顯示所有函數的棧幀以及父棧幀標籤。",
14 | "pythonPreview.hideCode.desc": "隱藏代碼顯示。",
15 | "pythonPreview.codAndNavWidth": "設置代碼和導航區域寬度。",
16 | "pythonPreview.allowAllModules.desc": "設置是否可以導入所有模塊。",
17 | "pythonPreview.maxExecutedLines.desc": "設置執行行數的最大值,以防無線的循環。",
18 | "pythonPreview.cumulativeMode.desc": "顯示所有已退出的棧幀,而不僅是當前堆棧。",
19 | "pythonPreview.trace.desc": "允許 python-preview 拓展啟用調試日誌記錄。",
20 |
21 | "pythonPreview.fontFamily.desc": "控制 python 預覽中使用的字體系列。",
22 | "pythonPreview.fontSize.desc": "控制 python 預覽中使用的字號(以像素為單位)。",
23 | "pythonPreview.langDisplay.fontFamily.desc": "控制語言顯示區域中使用的字體系列。",
24 | "pythonPreview.langDisplay.fontSize.desc": "控制語言顯示區域中使用的字號(以像素為單位)。",
25 | "pythonPreview.code.fontFamily.desc": "控制代碼顯示區域中使用的字體系列。",
26 | "pythonPreview.code.fontSize.desc": "控制代碼顯示區域中使用的字號(以像素為單位)。",
27 | "pythonPreview.code.lineHeight.desc": "控制代碼顯示區域中使用的行高。",
28 | "pythonPreview.legend.fontFamily.desc": "控制箭頭圖列中使用的字體系列。",
29 | "pythonPreview.legend.fontSize.desc": "控制箭頭圖列中使用的字號(以像素為單位)。",
30 | "pythonPreview.codeFooterDocs.fontFamily.desc": "控制代碼頁腳文檔中使用的字體系列。",
31 | "pythonPreview.codeFooterDocs.fontSize.desc": "控制代碼頁腳文檔中使用的字號(以像素為單位)。",
32 | "pythonPreview.printOutputDocs.fontFamily.desc": "控制打印輸出文檔中使用的字體系列。",
33 | "pythonPreview.printOutoutDocs.fontSize.desc": "控制打印輸出文檔中使用的字號(以像素為單位)。",
34 | "pythonPreview.pyStdout.fontFamily.desc": "控制 python 標準輸出窗口中使用的字體系列。",
35 | "pythonPreview.pyStdout.fontSize.desc": "控制 python 標準輸出窗口中使用的字號(以像素為單位)。",
36 | "pythonPreview.stackAndHeapHeader.fontFamily.desc": "控制棧頭部和堆頭部中使用的字體系列。",
37 | "pythonPreview.stackAndHeapHeader.fontSize.desc": "控制棧頭部和堆頭部中使用的字號(以像素為單位)。",
38 | "pythonPreview.stackFrame.fontFamily.desc": "控制棧幀中使用的字體系列。",
39 | "pythonPreview.stackFrame.fontSize.desc": "控制棧幀中使用的字號(以像素為單位)。",
40 | "pythonPreview.retVal.fontSize.desc": "控制函數返回值中使用的字號(以像素為單位)。",
41 | "pythonPreview.stackFrameHeader.fontFamily.desc": "控制棧幀頭部中使用的字體系列。",
42 | "pythonPreview.stackFrameHeader.fontSize.desc": "控制棧幀頭部中使用的字號(以像素為單位)。",
43 | "pythonPreview.heapObject.fontFamily.desc": "控制堆對象中使用的字體系列。",
44 | "pythonPreview.heapObject.fontSize.desc": "控制堆對象中使用的字號(以像素為單位)。",
45 | "pythonPreview.typeLabel.fontFamily.desc": "控制堆對象的類型標籤中使用的字體系列。",
46 | "pythonPreview.typeLabel.fontSize.desc": "控制堆對象的類型標籤中使用的字號(以像素為單位)。",
47 |
48 | "pythonPreview.light.highlightedArrow.color.desc": "控制 vscode 淺色主題下高亮箭頭使用的顏色。",
49 | "pythonPreview.light.highlightedStackFrame.bgColor.desc": "控制 vscode 淺色主題下高亮堆棧使用的背景色。",
50 | "pythonPreview.light.list-tuple-setTbl.bgColor.desc": "控制 vscode 淺色主題下列表、元祖和集合使用的背景色。",
51 | "pythonPreview.light.dict-class-instKey.bgColor.desc": "控制 vscode 淺色主題下字典、類和實例中鍵使用的背景色。",
52 | "pythonPreview.light.dict-class-instVal.bgColor.desc": "控制 vscode 淺色主題下字典、類和實例中值使用的背景色。",
53 | "pythonPreview.dark.highlightedArrow.color.desc": "控制 vscode 深色主題下高亮箭頭使用的顏色。",
54 | "pythonPreview.dark.highlightedStackFrame.bgColor.desc": "控制 vscode 深色主題下高亮堆棧使用的背景色。",
55 | "pythonPreview.dark.list-tuple-setTbl.bgColor.desc": "控制 vscode 深色主題下列表、元祖和集合使用的背景色。",
56 | "pythonPreview.dark.dict-class-instKey.bgColor.desc": "控制 vscode 深色主題下字典、類和實例中鍵使用的背景色。",
57 | "pythonPreview.dark.dict-class-instVal.bgColor.desc": "控制 vscode 深色主題下字典、類和實例中值使用的背景色。",
58 | "pythonPreview.high-contrast.highlightedArrow.color.desc": "控制 vscode 高對比度主題下高亮箭頭使用的顏色。",
59 | "pythonPreview.high-contrast.highlightedStackFrame.bgColor.desc": "控制 vscode 高對比度主題下高亮堆棧使用的背景色。",
60 | "pythonPreview.high-contrast.list-tuple-setTbl.bgColor.desc": "控制 vscode 高對比度主題下列表、元祖和集合使用的背景色。",
61 | "pythonPreview.high-contrast.dict-class-instKey.bgColor.desc": "控制 vscode 高對比度主題下字典、類和實例中鍵使用的背景色。",
62 | "pythonPreview.high-contrast.dict-class-instVal.bgColor.desc": "控制 vscode 高對比度主題下字典、類和實例中值使用的背景色。"
63 | }
--------------------------------------------------------------------------------
/preview-src/README.md:
--------------------------------------------------------------------------------
1 | For developing using TypeScript:
2 | 1. run 'npm install typings -g'.
3 | 2. run 'typings install' (to install definition moduels saved in typings.json).
--------------------------------------------------------------------------------
/preview-src/datas.ts:
--------------------------------------------------------------------------------
1 | export interface PreviewState {
2 | resource: string,
3 | locked: boolean,
4 | startingInstruction: number,
5 | width: number
6 | }
7 |
8 | export function getDataState(): PreviewState {
9 | const element = document.getElementById('vscode-python-preview-data');
10 | if (element) {
11 | const dataState = element.getAttribute('data-state')
12 | if (dataState) {
13 | return JSON.parse(dataState);
14 | }
15 | }
16 |
17 | throw new Error(`Could not load data state`);
18 | }
--------------------------------------------------------------------------------
/preview-src/events.ts:
--------------------------------------------------------------------------------
1 | export function onceDocumentLoaded(f: () => void) {
2 | if (document.readyState === 'loading') {
3 | document.addEventListener('DOMContentLoaded', f);
4 | } else {
5 | f();
6 | }
7 | }
--------------------------------------------------------------------------------
/preview-src/index.ts:
--------------------------------------------------------------------------------
1 | import { ExecutionVisualizer } from "./pytutor";
2 | import { getDataState } from "./datas";
3 | import { createPosterForVsCode } from "./messaging";
4 |
5 | declare var acquireVsCodeApi: any;
6 |
7 | const vscode = acquireVsCodeApi();
8 |
9 | // 设置vscode状态
10 | const state = getDataState();
11 | vscode.setState(state);
12 |
13 | const messagePoster = createPosterForVsCode(vscode);
14 | let pyOutputPane: ExecutionVisualizer | undefined;
15 |
16 |
17 | window.addEventListener('message', event => {
18 | switch(event.data.type) {
19 | case 'updateContent':
20 | event.data.options.updateOutputCallback = visualizer => {
21 | state.startingInstruction = visualizer.curInstr;
22 | vscode.setState(state);
23 | messagePoster.postMessage('updateStartingInstruction', { curInstr: visualizer.curInstr });
24 | }
25 | pyOutputPane = new ExecutionVisualizer('pyOutputPane', event.data.data, event.data.options);
26 | pyOutputPane.redrawConnectors();
27 | break;
28 | case 'updateLock':
29 | state.locked = event.data.locked;
30 | vscode.setState(state);
31 | break;
32 | }
33 | });
34 |
35 | $(window).resize(() => {
36 | if (pyOutputPane) {
37 | pyOutputPane.redrawConnectors();
38 | let width = document.getElementById('codAndNav').style['width'];
39 | state.width = parseFloat(width.slice(0, -2));
40 | messagePoster.postMessage('updateCodAndNavWidth', { width: state.width });
41 | }
42 | });
--------------------------------------------------------------------------------
/preview-src/lib/jquery-ui-1.11.4/images/ui-bg_diagonals-thick_18_b81900_40x40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongli0x00/python-preview/f574a46aad9a0483fcfd1ad331405cce6e15b8d9/preview-src/lib/jquery-ui-1.11.4/images/ui-bg_diagonals-thick_18_b81900_40x40.png
--------------------------------------------------------------------------------
/preview-src/lib/jquery-ui-1.11.4/images/ui-bg_diagonals-thick_20_666666_40x40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongli0x00/python-preview/f574a46aad9a0483fcfd1ad331405cce6e15b8d9/preview-src/lib/jquery-ui-1.11.4/images/ui-bg_diagonals-thick_20_666666_40x40.png
--------------------------------------------------------------------------------
/preview-src/lib/jquery-ui-1.11.4/images/ui-bg_flat_10_000000_40x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongli0x00/python-preview/f574a46aad9a0483fcfd1ad331405cce6e15b8d9/preview-src/lib/jquery-ui-1.11.4/images/ui-bg_flat_10_000000_40x100.png
--------------------------------------------------------------------------------
/preview-src/lib/jquery-ui-1.11.4/images/ui-bg_glass_100_f6f6f6_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongli0x00/python-preview/f574a46aad9a0483fcfd1ad331405cce6e15b8d9/preview-src/lib/jquery-ui-1.11.4/images/ui-bg_glass_100_f6f6f6_1x400.png
--------------------------------------------------------------------------------
/preview-src/lib/jquery-ui-1.11.4/images/ui-bg_glass_100_fdf5ce_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongli0x00/python-preview/f574a46aad9a0483fcfd1ad331405cce6e15b8d9/preview-src/lib/jquery-ui-1.11.4/images/ui-bg_glass_100_fdf5ce_1x400.png
--------------------------------------------------------------------------------
/preview-src/lib/jquery-ui-1.11.4/images/ui-bg_glass_65_ffffff_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongli0x00/python-preview/f574a46aad9a0483fcfd1ad331405cce6e15b8d9/preview-src/lib/jquery-ui-1.11.4/images/ui-bg_glass_65_ffffff_1x400.png
--------------------------------------------------------------------------------
/preview-src/lib/jquery-ui-1.11.4/images/ui-bg_gloss-wave_35_f6a828_500x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongli0x00/python-preview/f574a46aad9a0483fcfd1ad331405cce6e15b8d9/preview-src/lib/jquery-ui-1.11.4/images/ui-bg_gloss-wave_35_f6a828_500x100.png
--------------------------------------------------------------------------------
/preview-src/lib/jquery-ui-1.11.4/images/ui-bg_highlight-soft_100_eeeeee_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongli0x00/python-preview/f574a46aad9a0483fcfd1ad331405cce6e15b8d9/preview-src/lib/jquery-ui-1.11.4/images/ui-bg_highlight-soft_100_eeeeee_1x100.png
--------------------------------------------------------------------------------
/preview-src/lib/jquery-ui-1.11.4/images/ui-bg_highlight-soft_75_ffe45c_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongli0x00/python-preview/f574a46aad9a0483fcfd1ad331405cce6e15b8d9/preview-src/lib/jquery-ui-1.11.4/images/ui-bg_highlight-soft_75_ffe45c_1x100.png
--------------------------------------------------------------------------------
/preview-src/lib/jquery-ui-1.11.4/images/ui-icons_222222_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongli0x00/python-preview/f574a46aad9a0483fcfd1ad331405cce6e15b8d9/preview-src/lib/jquery-ui-1.11.4/images/ui-icons_222222_256x240.png
--------------------------------------------------------------------------------
/preview-src/lib/jquery-ui-1.11.4/images/ui-icons_228ef1_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongli0x00/python-preview/f574a46aad9a0483fcfd1ad331405cce6e15b8d9/preview-src/lib/jquery-ui-1.11.4/images/ui-icons_228ef1_256x240.png
--------------------------------------------------------------------------------
/preview-src/lib/jquery-ui-1.11.4/images/ui-icons_ef8c08_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongli0x00/python-preview/f574a46aad9a0483fcfd1ad331405cce6e15b8d9/preview-src/lib/jquery-ui-1.11.4/images/ui-icons_ef8c08_256x240.png
--------------------------------------------------------------------------------
/preview-src/lib/jquery-ui-1.11.4/images/ui-icons_ffd27a_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongli0x00/python-preview/f574a46aad9a0483fcfd1ad331405cce6e15b8d9/preview-src/lib/jquery-ui-1.11.4/images/ui-icons_ffd27a_256x240.png
--------------------------------------------------------------------------------
/preview-src/lib/jquery-ui-1.11.4/images/ui-icons_ffffff_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongli0x00/python-preview/f574a46aad9a0483fcfd1ad331405cce6e15b8d9/preview-src/lib/jquery-ui-1.11.4/images/ui-icons_ffffff_256x240.png
--------------------------------------------------------------------------------
/preview-src/lib/jquery-ui-1.11.4/jquery-ui.structure.min.css:
--------------------------------------------------------------------------------
1 | /*! jQuery UI - v1.11.4 - 2015-03-11
2 | * http://jqueryui.com
3 | * Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */
4 |
5 | .ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-accordion .ui-accordion-header{display:block;cursor:pointer;position:relative;margin:2px 0 0 0;padding:.5em .5em .5em .7em;min-height:0;font-size:100%}.ui-accordion .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-icons .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-header .ui-accordion-header-icon{position:absolute;left:.5em;top:50%;margin-top:-8px}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;overflow:auto}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-button{display:inline-block;position:relative;padding:0;line-height:normal;margin-right:.1em;cursor:pointer;vertical-align:middle;text-align:center;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2.2em}button.ui-button-icon-only{width:2.4em}.ui-button-icons-only{width:3.4em}button.ui-button-icons-only{width:3.7em}.ui-button .ui-button-text{display:block;line-height:normal}.ui-button-text-only .ui-button-text{padding:.4em 1em}.ui-button-icon-only .ui-button-text,.ui-button-icons-only .ui-button-text{padding:.4em;text-indent:-9999999px}.ui-button-text-icon-primary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 1em .4em 2.1em}.ui-button-text-icon-secondary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 2.1em .4em 1em}.ui-button-text-icons .ui-button-text{padding-left:2.1em;padding-right:2.1em}input.ui-button{padding:.4em 1em}.ui-button-icon-only .ui-icon,.ui-button-text-icon-primary .ui-icon,.ui-button-text-icon-secondary .ui-icon,.ui-button-text-icons .ui-icon,.ui-button-icons-only .ui-icon{position:absolute;top:50%;margin-top:-8px}.ui-button-icon-only .ui-icon{left:50%;margin-left:-8px}.ui-button-text-icon-primary .ui-button-icon-primary,.ui-button-text-icons .ui-button-icon-primary,.ui-button-icons-only .ui-button-icon-primary{left:.5em}.ui-button-text-icon-secondary .ui-button-icon-secondary,.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em}.ui-buttonset{margin-right:7px}.ui-buttonset .ui-button{margin-left:0;margin-right:-.3em}input.ui-button::-moz-focus-inner,button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:45%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-dialog{overflow:hidden;position:absolute;top:0;left:0;padding:.2em;outline:0}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 0;white-space:nowrap;width:90%;overflow:hidden;text-overflow:ellipsis}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:20px;margin:-10px 0 0 0;padding:1px;height:20px}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin-top:.5em;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-se{width:12px;height:12px;right:-5px;bottom:-5px;background-position:16px 16px}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-draggable-handle{-ms-touch-action:none;touch-action:none}.ui-menu{list-style:none;padding:0;margin:0;display:block;outline:none}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{position:relative;margin:0;padding:3px 1em 3px .4em;cursor:pointer;min-height:0;list-style-image:url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7")}.ui-menu .ui-menu-divider{margin:5px 0;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-state-focus,.ui-menu .ui-state-active{margin:-1px}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item{padding-left:2em}.ui-menu .ui-icon{position:absolute;top:0;bottom:0;left:.2em;margin:auto 0}.ui-menu .ui-menu-icon{left:auto;right:0}.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-progressbar .ui-progressbar-overlay{background:url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmoqCe5mGhZOfeYSUh5yJcJyrkZWWpaR8doJ2o4NYq62lAAACH5BAkBAAEALAAAAAAoACgAAAKVDI4Yy22ZnINRNqosw0Bv7i1gyHUkFj7oSaWlu3ovC8GxNso5fluz3qLVhBVeT/Lz7ZTHyxL5dDalQWPVOsQWtRnuwXaFTj9jVVh8pma9JjZ4zYSj5ZOyma7uuolffh+IR5aW97cHuBUXKGKXlKjn+DiHWMcYJah4N0lYCMlJOXipGRr5qdgoSTrqWSq6WFl2ypoaUAAAIfkECQEAAQAsAAAAACgAKAAAApaEb6HLgd/iO7FNWtcFWe+ufODGjRfoiJ2akShbueb0wtI50zm02pbvwfWEMWBQ1zKGlLIhskiEPm9R6vRXxV4ZzWT2yHOGpWMyorblKlNp8HmHEb/lCXjcW7bmtXP8Xt229OVWR1fod2eWqNfHuMjXCPkIGNileOiImVmCOEmoSfn3yXlJWmoHGhqp6ilYuWYpmTqKUgAAIfkECQEAAQAsAAAAACgAKAAAApiEH6kb58biQ3FNWtMFWW3eNVcojuFGfqnZqSebuS06w5V80/X02pKe8zFwP6EFWOT1lDFk8rGERh1TTNOocQ61Hm4Xm2VexUHpzjymViHrFbiELsefVrn6XKfnt2Q9G/+Xdie499XHd2g4h7ioOGhXGJboGAnXSBnoBwKYyfioubZJ2Hn0RuRZaflZOil56Zp6iioKSXpUAAAh+QQJAQABACwAAAAAKAAoAAACkoQRqRvnxuI7kU1a1UU5bd5tnSeOZXhmn5lWK3qNTWvRdQxP8qvaC+/yaYQzXO7BMvaUEmJRd3TsiMAgswmNYrSgZdYrTX6tSHGZO73ezuAw2uxuQ+BbeZfMxsexY35+/Qe4J1inV0g4x3WHuMhIl2jXOKT2Q+VU5fgoSUI52VfZyfkJGkha6jmY+aaYdirq+lQAACH5BAkBAAEALAAAAAAoACgAAAKWBIKpYe0L3YNKToqswUlvznigd4wiR4KhZrKt9Upqip61i9E3vMvxRdHlbEFiEXfk9YARYxOZZD6VQ2pUunBmtRXo1Lf8hMVVcNl8JafV38aM2/Fu5V16Bn63r6xt97j09+MXSFi4BniGFae3hzbH9+hYBzkpuUh5aZmHuanZOZgIuvbGiNeomCnaxxap2upaCZsq+1kAACH5BAkBAAEALAAAAAAoACgAAAKXjI8By5zf4kOxTVrXNVlv1X0d8IGZGKLnNpYtm8Lr9cqVeuOSvfOW79D9aDHizNhDJidFZhNydEahOaDH6nomtJjp1tutKoNWkvA6JqfRVLHU/QUfau9l2x7G54d1fl995xcIGAdXqMfBNadoYrhH+Mg2KBlpVpbluCiXmMnZ2Sh4GBqJ+ckIOqqJ6LmKSllZmsoq6wpQAAAh+QQJAQABACwAAAAAKAAoAAAClYx/oLvoxuJDkU1a1YUZbJ59nSd2ZXhWqbRa2/gF8Gu2DY3iqs7yrq+xBYEkYvFSM8aSSObE+ZgRl1BHFZNr7pRCavZ5BW2142hY3AN/zWtsmf12p9XxxFl2lpLn1rseztfXZjdIWIf2s5dItwjYKBgo9yg5pHgzJXTEeGlZuenpyPmpGQoKOWkYmSpaSnqKileI2FAAACH5BAkBAAEALAAAAAAoACgAAAKVjB+gu+jG4kORTVrVhRlsnn2dJ3ZleFaptFrb+CXmO9OozeL5VfP99HvAWhpiUdcwkpBH3825AwYdU8xTqlLGhtCosArKMpvfa1mMRae9VvWZfeB2XfPkeLmm18lUcBj+p5dnN8jXZ3YIGEhYuOUn45aoCDkp16hl5IjYJvjWKcnoGQpqyPlpOhr3aElaqrq56Bq7VAAAOw==");height:100%;filter:alpha(opacity=25);opacity:0.25}.ui-progressbar-indeterminate .ui-progressbar-value{background-image:none}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block;-ms-touch-action:none;touch-action:none}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-selectable{-ms-touch-action:none;touch-action:none}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted black}.ui-selectmenu-menu{padding:0;margin:0;position:absolute;top:0;left:0;display:none}.ui-selectmenu-menu .ui-menu{overflow:auto;overflow-x:hidden;padding-bottom:1px}.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup{font-size:1em;font-weight:bold;line-height:1.5;padding:2px 0.4em;margin:0.5em 0 0 0;height:auto;border:0}.ui-selectmenu-open{display:block}.ui-selectmenu-button{display:inline-block;overflow:hidden;position:relative;text-decoration:none;cursor:pointer}.ui-selectmenu-button span.ui-icon{right:0.5em;left:auto;margin-top:-8px;position:absolute;top:50%}.ui-selectmenu-button span.ui-selectmenu-text{text-align:left;padding:0.4em 2.1em 0.4em 1em;display:block;line-height:1.4;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default;-ms-touch-action:none;touch-action:none}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider.ui-state-disabled .ui-slider-handle,.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-sortable-handle{-ms-touch-action:none;touch-action:none}.ui-spinner{position:relative;display:inline-block;overflow:hidden;padding:0;vertical-align:middle}.ui-spinner-input{border:none;background:none;color:inherit;padding:0;margin:.2em 0;vertical-align:middle;margin-left:.4em;margin-right:22px}.ui-spinner-button{width:16px;height:50%;font-size:.5em;padding:0;margin:0;text-align:center;position:absolute;cursor:default;display:block;overflow:hidden;right:0}.ui-spinner a.ui-spinner-button{border-top:none;border-bottom:none;border-right:none}.ui-spinner .ui-icon{position:absolute;margin-top:-8px;top:50%;left:0}.ui-spinner-up{top:0}.ui-spinner-down{bottom:0}.ui-spinner .ui-icon-triangle-1-s{background-position:-65px -16px}.ui-tabs{position:relative;padding:.2em}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom-width:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav .ui-tabs-anchor{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor{cursor:text}.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none}.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px;-webkit-box-shadow:0 0 5px #aaa;box-shadow:0 0 5px #aaa}body .ui-tooltip{border-width:2px}
--------------------------------------------------------------------------------
/preview-src/lib/jquery-ui-1.11.4/jquery-ui.theme.min.css:
--------------------------------------------------------------------------------
1 | /*! jQuery UI - v1.11.4 - 2015-03-11
2 | * http://jqueryui.com
3 | * Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */
4 |
5 | .ui-widget{font-family:Trebuchet MS,Tahoma,Verdana,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Trebuchet MS,Tahoma,Verdana,Arial,sans-serif;font-size:1em}.ui-widget-content{border:1px solid #ddd;background:#eee url("images/ui-bg_highlight-soft_100_eeeeee_1x100.png") 50% top repeat-x;color:#333}.ui-widget-content a{color:#333}.ui-widget-header{border:1px solid #e78f08;background:#f6a828 url("images/ui-bg_gloss-wave_35_f6a828_500x100.png") 50% 50% repeat-x;color:#fff;font-weight:bold}.ui-widget-header a{color:#fff}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #ccc;background:#f6f6f6 url("images/ui-bg_glass_100_f6f6f6_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#1c94c4}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#1c94c4;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #fbcb09;background:#fdf5ce url("images/ui-bg_glass_100_fdf5ce_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#c77405}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited,.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited{color:#c77405;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #fbd850;background:#fff url("images/ui-bg_glass_65_ffffff_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#eb8f00}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#eb8f00;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #fed22f;background:#ffe45c url("images/ui-bg_highlight-soft_75_ffe45c_1x100.png") 50% top repeat-x;color:#363636}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#363636}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #cd0a0a;background:#b81900 url("images/ui-bg_diagonals-thick_18_b81900_40x40.png") 50% 50% repeat;color:#fff}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#fff}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#fff}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url("images/ui-icons_222222_256x240.png")}.ui-widget-header .ui-icon{background-image:url("images/ui-icons_ffffff_256x240.png")}.ui-state-default .ui-icon{background-image:url("images/ui-icons_ef8c08_256x240.png")}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url("images/ui-icons_ef8c08_256x240.png")}.ui-state-active .ui-icon{background-image:url("images/ui-icons_ef8c08_256x240.png")}.ui-state-highlight .ui-icon{background-image:url("images/ui-icons_228ef1_256x240.png")}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url("images/ui-icons_ffd27a_256x240.png")}.ui-icon-blank{background-position:16px 16px}.ui-icon-carat-1-n{background-position:0 0}.ui-icon-carat-1-ne{background-position:-16px 0}.ui-icon-carat-1-e{background-position:-32px 0}.ui-icon-carat-1-se{background-position:-48px 0}.ui-icon-carat-1-s{background-position:-64px 0}.ui-icon-carat-1-sw{background-position:-80px 0}.ui-icon-carat-1-w{background-position:-96px 0}.ui-icon-carat-1-nw{background-position:-112px 0}.ui-icon-carat-2-n-s{background-position:-128px 0}.ui-icon-carat-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-64px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-64px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:0 -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:4px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:4px}.ui-widget-overlay{background:#666 url("images/ui-bg_diagonals-thick_20_666666_40x40.png") 50% 50% repeat;opacity:.5;filter:Alpha(Opacity=50)}.ui-widget-shadow{margin:-5px 0 0 -5px;padding:5px;background:#000 url("images/ui-bg_flat_10_000000_40x100.png") 50% 50% repeat-x;opacity:.2;filter:Alpha(Opacity=20);border-radius:5px}
--------------------------------------------------------------------------------
/preview-src/messaging.ts:
--------------------------------------------------------------------------------
1 | import { getDataState } from "./datas";
2 |
3 | export interface MessagePoster {
4 | postMessage(type: string, body: object): void;
5 |
6 | postCommand(command: string, args: any[]): void;
7 | }
8 |
9 | export const createPosterForVsCode = (vscode: any) => {
10 | return new class implements MessagePoster {
11 | postMessage(type: string, body: object): void {
12 | vscode.postMessage({
13 | type: type,
14 | source: getDataState().resource,
15 | body: body
16 | });
17 | }
18 |
19 | postCommand(command: string, args: any[]) {
20 | this.postMessage('command', { command, args });
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/preview-src/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "preview-src",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "install-lib-typings": "typings install",
8 | "dev": "webpack --progress --colors --config webpack.dev.js",
9 | "prod": "webpack --progress --colors --config webpack.prod.js"
10 | },
11 | "keywords": [],
12 | "author": "",
13 | "license": "BSD-3-Clause",
14 | "devDependencies": {
15 | "clean-webpack-plugin": "^0.1.19",
16 | "ts-loader": "^3.5.0",
17 | "typescript": "^2.8.3",
18 | "uglifyjs-webpack-plugin": "^1.3.0",
19 | "webpack": "^3.11.0",
20 | "webpack-merge": "^4.1.4"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/preview-src/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "es6",
5 | "sourceMap": true
6 | },
7 | "exclude": [
8 | "node_modules"
9 | ]
10 | }
--------------------------------------------------------------------------------
/preview-src/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "preview-src",
3 | "globalDependencies": {
4 | "require": "github:DefinitelyTyped/DefinitelyTyped/requirejs/require.d.ts#1315d46f8066eec8c197914da88e98629ebc2254",
5 | "jquery": "github:DefinitelyTyped/DefinitelyTyped/jquery/jquery.d.ts#1315d46f8066eec8c197914da88e98629ebc2254",
6 | "jquery.bbq": "github:DefinitelyTyped/DefinitelyTyped/jquery.bbq/jquery.bbq.d.ts#1315d46f8066eec8c197914da88e98629ebc2254",
7 | "ace": "github:DefinitelyTyped/DefinitelyTyped/ace/ace.d.ts#1315d46f8066eec8c197914da88e98629ebc2254",
8 | "qtip2": "github:DefinitelyTyped/DefinitelyTyped/qtip2/qtip2.d.ts#1315d46f8066eec8c197914da88e98629ebc2254",
9 | "jqueryui": "github:DefinitelyTyped/DefinitelyTyped/jqueryui/jqueryui.d.ts#1315d46f8066eec8c197914da88e98629ebc2254",
10 | "d3": "github:DefinitelyTyped/DefinitelyTyped/d3/d3.d.ts#1315d46f8066eec8c197914da88e98629ebc2254",
11 | "diff-match-patch": "github:DefinitelyTyped/DefinitelyTyped/diff-match-patch/diff-match-patch.d.ts#1315d46f8066eec8c197914da88e98629ebc2254",
12 | "jquery.simplemodal": "github:DefinitelyTyped/DefinitelyTyped/jquery.simplemodal/jquery.simplemodal.d.ts#1315d46f8066eec8c197914da88e98629ebc2254"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/preview-src/webpack.common.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const webpack = require('webpack');
3 |
4 | module.exports = {
5 | entry: './index.ts',
6 |
7 | output: {
8 | path: path.resolve(__dirname, '..', 'assets'),
9 | filename: 'index.js'
10 | },
11 |
12 | module: {
13 | loaders: [
14 | {
15 | test: /\.ts$/,
16 | loader: 'ts-loader'
17 | }
18 | ]
19 | },
20 |
21 | resolve: {
22 | extensions: ['.ts', '.js'],
23 | alias: {
24 | "jquery": path.resolve(__dirname, 'lib', 'jquery-3.0.0.min.js'),
25 | "$": path.resolve(__dirname, 'lib', 'jquery-3.0.0.min.js'),
26 | "$.bbq": path.resolve(__dirname, 'lib', 'jquery.ba-bbq.js')
27 | }
28 | },
29 |
30 | plugins: [
31 | new webpack.ProvidePlugin({
32 | jquery: "jquery",
33 | jQuery: "jquery",
34 | $: 'jquery'
35 | })
36 | ]
37 | }
--------------------------------------------------------------------------------
/preview-src/webpack.dev.js:
--------------------------------------------------------------------------------
1 | const merge = require('webpack-merge');
2 | const common = require('./webpack.common.js');
3 |
4 | module.exports = merge(common, {
5 | // mode: 'development',
6 | devtool: 'inline-source-map'
7 | })
--------------------------------------------------------------------------------
/preview-src/webpack.prod.js:
--------------------------------------------------------------------------------
1 | const merge = require('webpack-merge');
2 | const common = require('./webpack.common.js');
3 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
4 |
5 | module.exports = merge(common, {
6 | plugins: [
7 | new UglifyJsPlugin({
8 | uglifyOptions: {
9 | warnings: false,
10 | output: {
11 | comments: false
12 | }
13 | }
14 | })
15 | ]
16 | })
--------------------------------------------------------------------------------
/python-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongli0x00/python-preview/f574a46aad9a0483fcfd1ad331405cce6e15b8d9/python-icon.png
--------------------------------------------------------------------------------
/pythonFiles/pydev/debugger.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import socket
3 | import traceback
4 | import pg_logger
5 | import json
6 |
7 | import util as _util
8 |
9 | to_bytes = _util.to_bytes
10 | to_str = _util.to_str
11 | read_bytes = _util.read_bytes
12 | write_bytes = _util.write_bytes
13 | read_int = _util.read_int
14 | write_int = _util.write_int
15 | read_string = _util.read_string
16 | write_string = _util.write_string
17 |
18 | try:
19 | xrange
20 | except:
21 | xrange = range
22 |
23 | LOAD = to_bytes('LOAD')
24 | OUTP = to_bytes('OUTP')
25 | DETC = to_bytes('DETC')
26 |
27 | def debug(port_num, debug_id, current_pid):
28 | attach_process(port_num, debug_id, current_pid)
29 |
30 | report_process_loaded()
31 |
32 | DebuggerLoop(conn).loop()
33 |
34 | def report_process_loaded():
35 | write_bytes(conn, LOAD)
36 | write_string(conn, '.'.join(map(str, sys.version_info)))
37 |
38 | def attach_process(port_num, debug_id, current_pid):
39 | global conn
40 | for i in xrange(50):
41 | try:
42 | conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
43 | conn.connect(('127.0.0.1', port_num))
44 | write_string(conn, debug_id)
45 | write_int(conn, 0) # success
46 | write_int(conn, current_pid) # success
47 | break
48 | except:
49 | import time
50 | time.sleep(50. / 1000)
51 | else:
52 | sys.stdout.write('&error&failed to attach')
53 | sys.stderr.flush()
54 | raise Exception('failed to attach')
55 |
56 |
57 | class DebuggerExitException(Exception): pass
58 |
59 |
60 | class DebuggerLoop:
61 | instacne = None
62 |
63 | def __init__(self, conn):
64 | DebuggerLoop.instacne = self
65 | self._conn = conn
66 | self._command_table = {
67 | to_bytes('outp'): self.command_exec_script,
68 | to_bytes('detc'): self.command_detach
69 | }
70 |
71 | def loop(self):
72 | try:
73 | while True:
74 | index = read_bytes(self._conn, 4)
75 | cmd = self._command_table.get(index)
76 | if cmd is not None:
77 | cmd()
78 | else:
79 | if index:
80 | sys.stdout.write('&warn&unknown command: %s' % to_str(index))
81 | sys.stdout.flush()
82 | print('unknown command', index)
83 | break
84 | except DebuggerExitException:
85 | pass
86 | except socket.error:
87 | pass
88 | except:
89 | traceback.print_exc()
90 |
91 | def command_exec_script(self):
92 | raw_input_lst_json = False
93 | heap_primitives = False
94 | cumulative_mode = read_int(self._conn)
95 | if cumulative_mode == 0:
96 | cumulative_mode = False
97 | else:
98 | cumulative_mode = True
99 | allow_all_modules = read_int(self._conn)
100 | if allow_all_modules == 0:
101 | allow_all_modules = False
102 | else:
103 | allow_all_modules = True
104 | max_executed_lines = read_int(self._conn)
105 | folder = read_string(self._conn)
106 | sys.path[0] = folder
107 | resource = read_string(self._conn)
108 | script_str = read_string(self._conn)
109 | trace_str = pg_logger.exec_script_str_local(script_str, raw_input_lst_json, cumulative_mode, heap_primitives, max_executed_lines, json_finalizer, probe_exprs=None, allow_all_modules=allow_all_modules)
110 | write_bytes(self._conn, OUTP)
111 | write_string(self._conn, resource)
112 | write_string(self._conn, trace_str)
113 |
114 | def command_detach(self):
115 | write_bytes(self._conn, DETC)
116 |
117 |
118 | def json_finalizer(input_code, output_trace):
119 | ret = dict(code=input_code, trace=output_trace)
120 | json_output = json.dumps(ret, indent=0)
121 | return json_output
--------------------------------------------------------------------------------
/pythonFiles/pydev/launcher.py:
--------------------------------------------------------------------------------
1 | import os
2 | import os.path
3 | import sys
4 | import traceback
5 | sys.stdout.write('&info&succeeded to launch script')
6 | sys.stdout.flush()
7 | try:
8 | import debugger
9 | except:
10 | traceback.print_exc()
11 | print('Press Enter to close...')
12 | try:
13 | raw_input()
14 | except NameError:
15 | input()
16 | sys.exit(1)
17 |
18 |
19 | #=======================================================================================================================
20 | # 1. Debugger port to connect to.
21 | # 2. GUID for the debug session.
22 | # 3. Startup script name.
23 | #=======================================================================================================================
24 | port_num = int(sys.argv[1])
25 | debug_id = sys.argv[2]
26 | del sys.argv[1:3]
27 |
28 | # filename = sys.argv[0]
29 |
30 | sys.path[0] = ''
31 |
32 | current_pid = os.getpid()
33 |
34 | del sys, os
35 |
36 | print(current_pid)
37 |
38 | debugger.debug(port_num, debug_id, current_pid)
--------------------------------------------------------------------------------
/pythonFiles/pydev/util.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import struct
3 | from encodings import utf_8, ascii
4 |
5 | try:
6 | unicode
7 | except:
8 | unicode = str
9 |
10 | try:
11 | xrange
12 | except:
13 | xrange = range
14 |
15 | if sys.version_info[0] >= 3:
16 | def to_bytes(cmd_str):
17 | return ascii.Codec.encode(cmd_str)[0]
18 | else:
19 | def to_bytes(cmd_str):
20 | return cmd_str
21 |
22 | if sys.version_info[0] >= 3:
23 | def to_str(cmd_bytes):
24 | return ascii.Codec.decode(cmd_bytes)[0]
25 | else:
26 | def to_str(cmd_bytes):
27 | return cmd_bytes
28 |
29 |
30 | UNICODE_PREFIX = to_bytes('U')
31 | ASCII_PREFIX = to_bytes('A')
32 | NONE_PREFIX = to_bytes('N')
33 |
34 |
35 | def read_bytes(conn, count):
36 | b = to_bytes('')
37 | while len(b) < count:
38 | received_data = conn.recv(count - len(b))
39 | if received_data is None:
40 | break
41 | b += received_data
42 | return b
43 |
44 |
45 | def write_bytes(conn, b):
46 | conn.sendall(b)
47 |
48 |
49 | def read_int(conn):
50 | # '!' represents network(=big-endian) byte order
51 | # 'q' represent long long in c type, integer in python type, 8 standard size
52 | return struct.unpack('!q', read_bytes(conn, 8))[0]
53 |
54 |
55 | def write_int(conn, i):
56 | write_bytes(conn, struct.pack('!q', i))
57 |
58 |
59 | def read_string(conn):
60 | str_len = read_int(conn)
61 | if not str_len:
62 | return ''
63 | res = to_bytes('')
64 | while len(res) < str_len:
65 | res = res + conn.recv(str_len - len(res))
66 | res = utf_8.decode(res)[0]
67 | if sys.version_info[0] == 2:
68 | try:
69 | res = ascii.Codec.encode(res)[0]
70 | except UnicodeEncodeError:
71 | pass
72 | return res
73 |
74 |
75 | def write_string(conn, s):
76 | if s is None:
77 | write_bytes(conn, NONE_PREFIX)
78 | elif isinstance(s, unicode):
79 | b = utf_8.encode(s)[0]
80 | b_len = len(b)
81 | write_bytes(conn, UNICODE_PREFIX)
82 | write_int(conn, b_len)
83 | if b_len > 0:
84 | write_bytes(conn, b)
85 | else:
86 | s_len = len(s)
87 | write_bytes(conn, ASCII_PREFIX)
88 | write_int(conn, s_len)
89 | if s_len > 0:
90 | write_bytes(conn, s)
--------------------------------------------------------------------------------
/src/commands/index.ts:
--------------------------------------------------------------------------------
1 | export { ShowPreviewCommand, ShowPreviewToSideCommand, ShowLockedPreviewToSideCommand } from './showPreview';
2 | export { ShowSourceCommand } from './showSource';
3 | export { RefreshPreviewCommand } from './refreshPreview';
4 | export { ToggleLockCommand } from './toggleLock';
--------------------------------------------------------------------------------
/src/commands/refreshPreview.ts:
--------------------------------------------------------------------------------
1 | import { Command } from "../common/commandManager";
2 | import { PythonPreviewManager } from "../features/previewManager";
3 |
4 | export class RefreshPreviewCommand implements Command {
5 | public readonly id = 'pythonPreview.refresh';
6 |
7 | public constructor(private readonly _previewManager: PythonPreviewManager) { }
8 |
9 | public execute() {
10 | this._previewManager.refresh();
11 | }
12 | }
--------------------------------------------------------------------------------
/src/commands/showPreview.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import {Command} from "../common/commandManager";
3 | import {PythonPreviewManager} from "../features/previewManager";
4 |
5 | interface ShowPreviewSettings {
6 | readonly sideBySide: boolean;
7 | readonly locked: boolean;
8 | }
9 |
10 | async function showPreview(previewManager: PythonPreviewManager,
11 | uri: vscode.Uri | undefined,
12 | previewSettings: ShowPreviewSettings): Promise {
13 | let resource = uri;
14 | if (!(resource instanceof vscode.Uri)) {
15 | if (vscode.window.activeTextEditor) {
16 | resource = vscode.window.activeTextEditor.document.uri;
17 | } else {
18 | return vscode.commands.executeCommand('pythonPreview.showSource');
19 | }
20 | }
21 |
22 | previewManager.preview(resource, {
23 | resourceColumn: (vscode.window.activeTextEditor && vscode.window.activeTextEditor.viewColumn) || vscode.ViewColumn.One,
24 | previewColumn: previewSettings.sideBySide ? vscode.ViewColumn.Beside : vscode.ViewColumn.Active,
25 | locked: previewSettings.locked
26 | });
27 | }
28 |
29 | /**
30 | *
31 | */
32 | export class ShowPreviewCommand implements Command {
33 | public readonly id = 'pythonPreview.showPreview';
34 |
35 | public constructor(private readonly _prviewManager: PythonPreviewManager) { }
36 |
37 | public execute() {
38 | showPreview(this._prviewManager, undefined, {
39 | sideBySide: false,
40 | locked: false
41 | });
42 | }
43 | }
44 |
45 |
46 | export class ShowPreviewToSideCommand implements Command {
47 | public readonly id = 'pythonPreview.showPreviewToSide';
48 |
49 | public constructor(private readonly _previewManager: PythonPreviewManager) { }
50 |
51 | public execute() {
52 | showPreview(this._previewManager, undefined, {
53 | sideBySide: true,
54 | locked: false
55 | });
56 | }
57 | }
58 |
59 | export class ShowLockedPreviewToSideCommand implements Command {
60 | public readonly id = 'pythonPreview.showLockedPreviewToSide';
61 |
62 | public constructor(private readonly _previewManager: PythonPreviewManager) { }
63 |
64 | public execute() {
65 | showPreview(this._previewManager, undefined, {
66 | sideBySide: true,
67 | locked: true
68 | });
69 | }
70 | }
--------------------------------------------------------------------------------
/src/commands/showSource.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import {Command} from "../common/commandManager";
3 | import {PythonPreviewManager} from "../features/previewManager";
4 |
5 | export class ShowSourceCommand implements Command {
6 | public readonly id = 'pythonPreview.showSource';
7 |
8 | public constructor(private readonly _previewManager: PythonPreviewManager) {
9 |
10 | }
11 |
12 | public execute() {
13 | if (this._previewManager.activePreviewResource) {
14 | return vscode.workspace.openTextDocument(this._previewManager.activePreviewResource)
15 | .then(document => vscode.window.showTextDocument(document));
16 | }
17 | return undefined;
18 | }
19 | }
--------------------------------------------------------------------------------
/src/commands/toggleLock.ts:
--------------------------------------------------------------------------------
1 | import { Command } from "../common/commandManager";
2 | import { PythonPreviewManager } from "../features/previewManager";
3 |
4 | export class ToggleLockCommand implements Command {
5 | public readonly id = 'pythonPreview.toggleLock';
6 |
7 | public constructor(private readonly _previewManager: PythonPreviewManager) {
8 |
9 | }
10 |
11 | public execute() {
12 | this._previewManager.toggleLock();
13 | }
14 | }
--------------------------------------------------------------------------------
/src/common/commandManager.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 |
3 | export interface Command {
4 | readonly id: string;
5 |
6 | execute(...args: any[]): void;
7 | }
8 |
9 | export class CommandManager {
10 | private readonly _commands = new Map();
11 |
12 | public dispose() {
13 | for (const registration of this._commands.values()) {
14 | registration.dispose();
15 | }
16 | this._commands.clear();
17 | }
18 |
19 | public register(command: T): T {
20 | this.registerCommand(command.id, command.execute, command);
21 | return command;
22 | }
23 |
24 | private registerCommand(id: string, impl: (...args: any[]) => void, thisArg?: any) {
25 | if (this._commands.has(id)) {
26 | return;
27 | }
28 |
29 | this._commands.set(id, vscode.commands.registerCommand(id, impl, thisArg));
30 | }
31 | }
--------------------------------------------------------------------------------
/src/common/dispose.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 |
3 | export function disposeAll(disposables: vscode.Disposable[]) {
4 | while (disposables.length) {
5 | const item = disposables.pop();
6 | if (item) {
7 | item.dispose();
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/src/common/file.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 |
3 | export function isPythonFile(document: vscode.TextDocument): boolean {
4 | return document.languageId === 'python';
5 | }
--------------------------------------------------------------------------------
/src/common/helpers.ts:
--------------------------------------------------------------------------------
1 | export function isNotInstalledError(error: Error): boolean {
2 | const isError = typeof(error) === 'object' && error != null;
3 | const errorObj = error;
4 | if (!isError) {
5 | return false;
6 | }
7 | const isModuleNotInstalledError = error.message.indexOf('No module named') >= 0;
8 | return errorObj.code === 'ENOENT' || errorObj.code === 127 || isModuleNotInstalledError;
9 | }
10 |
11 | export interface Deferred {
12 | readonly promise: Promise;
13 | readonly resolved: boolean;
14 | readonly rejected: boolean;
15 | readonly completed: boolean;
16 |
17 | resolve(value?: T | PromiseLike);
18 |
19 | reject(reason?: any);
20 | }
21 |
22 | class DeferredImpl implements Deferred {
23 | private _resolve!: (value?: T | PromiseLike) => void;
24 | private _reject!: (reason?: any) => void;
25 | private _resolved: boolean = false;
26 | private _rejected: boolean = false;
27 | private _promise: Promise;
28 |
29 | constructor(private _scope: any = null) {
30 | this._promise = new Promise((resolve, reject) => {
31 | this._resolve = resolve;
32 | this._reject = reject;
33 | });
34 | }
35 |
36 | public get promise(): Promise {
37 | return this._promise;
38 | }
39 |
40 | public get resolved(): boolean {
41 | return this._resolved;
42 | }
43 |
44 | public get rejected(): boolean {
45 | return this._rejected;
46 | }
47 |
48 | public get completed(): boolean {
49 | return this._resolved || this._rejected;
50 | }
51 |
52 | public resolve(value?: T | PromiseLike) {
53 | this._resolve.apply(this._scope ? this._scope : this, arguments);
54 | this._resolved = true;
55 | }
56 |
57 | public reject(reason?: any) {
58 | this._reject.apply(this._scope ? this._scope : this, arguments);
59 | this._rejected = true;
60 | }
61 | }
62 |
63 | export function createDeferred(scope: any = null): Deferred {
64 | return new DeferredImpl(scope);
65 | }
--------------------------------------------------------------------------------
/src/common/is.ts:
--------------------------------------------------------------------------------
1 | const toString = Object.prototype.toString;
2 |
3 | export function defined(value: any): boolean {
4 | return typeof value !== 'undefined';
5 | }
6 |
7 | export function boolean(value: any): value is boolean {
8 | return value === true || value === false;
9 | }
10 |
11 | export function string(value: any): value is string {
12 | return toString.call(value) === '[object String]';
13 | }
--------------------------------------------------------------------------------
/src/common/lazy.ts:
--------------------------------------------------------------------------------
1 | export interface Lazy {
2 | readonly hasValue: boolean;
3 | readonly value: T;
4 | map(f: (x: T) => R): Lazy;
5 | }
6 |
7 | class LazyValue implements Lazy {
8 | private _hasValue: boolean = false;
9 | private _value?: T;
10 |
11 | constructor(private readonly _getValue: () => T) { }
12 |
13 | get hasValue(): boolean {
14 | return this._hasValue;
15 | }
16 |
17 | get value(): T {
18 | if (!this._hasValue) {
19 | this._hasValue = true;
20 | this._value = this._getValue();
21 | }
22 | return this._value;
23 | }
24 |
25 | public map(f: (x: T) => R): Lazy {
26 | return new LazyValue(() => f(this.value));
27 | }
28 | }
29 |
30 | export function lazy(getValue: () => T): Lazy {
31 | return new LazyValue(getValue);
32 | }
--------------------------------------------------------------------------------
/src/common/logger.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import { lazy } from './lazy';
3 | import * as is from './is';
4 |
5 | enum Trace {
6 | Off,
7 | Verbose
8 | }
9 |
10 | namespace Trace {
11 | export function fromString(value: string): Trace {
12 | value = value.toLowerCase();
13 | switch (value) {
14 | case 'off':
15 | return Trace.Off;
16 | case 'verbose':
17 | return Trace.Verbose;
18 | default:
19 | return Trace.Off;
20 | }
21 | }
22 | }
23 |
24 | export class Logger {
25 | private _trace?: Trace;
26 |
27 | private readonly _outputChannel = lazy(() => vscode.window.createOutputChannel('PythonPreview'));
28 |
29 | constructor() {
30 | this.updateConfiguration();
31 | }
32 |
33 | public updateConfiguration() {
34 | this._trace = this.readTrace();
35 | }
36 |
37 | public info(message: string, data?: any): void {
38 | this.logLevel('Info', message, data);
39 | }
40 |
41 | public warn(message: string, data?: any): void {
42 | this.logLevel('Warn', message, data);
43 | }
44 |
45 | public error(message: string, data?: any): void {
46 | this.logLevel('Error', message, data);
47 | }
48 |
49 | public logLevel(level: string, message: string, data?: any): void {
50 | if (this._trace === Trace.Verbose) {
51 | this.appendLine(`[${level} - ${(new Date().toLocaleTimeString())}] ${message}`);
52 | if (data) {
53 | this.appendLine(Logger.data2String(data));
54 | }
55 | }
56 |
57 | }
58 |
59 | private appendLine(value: string) {
60 | this._outputChannel.value.appendLine(value);
61 | }
62 |
63 | private static data2String(data: any): string {
64 | if (data instanceof Error) {
65 | if (is.string(data.stack)) {
66 | return data.stack;
67 | }
68 | return (data as Error).message;
69 | }
70 | if (is.boolean(data.success) && !data.success && is.string(data.message)) {
71 | return data.message;
72 | }
73 | if (is.string(data)) {
74 | return data;
75 | }
76 | return data.toString();
77 | }
78 |
79 | private readTrace(): Trace {
80 | return Trace.fromString(vscode.workspace.getConfiguration().get('pythonPreview.trace', 'off'));
81 | }
82 | }
--------------------------------------------------------------------------------
/src/common/net/socket/socketStream.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import * as net from "net";
4 |
5 | const uint64be = require('uint64be');
6 |
7 | export class SocketStream {
8 | private _socket: net.Socket;
9 | private _buffer: Buffer;
10 | private _isInTransaction: boolean;
11 | private _bytesRead: number = 0;
12 | private _hasInsufficientDataForReading: boolean = false;
13 |
14 | public constructor(socket: net.Socket, buffer: Buffer) {
15 | this._socket = socket;
16 | this._buffer = buffer;
17 | }
18 |
19 | public get buffer(): Buffer {
20 | return this._buffer;
21 | }
22 |
23 | public get hasInsufficientDataForReading(): boolean {
24 | return this._hasInsufficientDataForReading;
25 | }
26 |
27 | public get length(): number {
28 | return this._buffer.length;
29 | }
30 |
31 | public writeInt32(num: number) {
32 | this.writeInt64(num);
33 | }
34 |
35 | public writeInt64(num: number) {
36 | let buffer = uint64be.encode(num);
37 | this._socket.write(buffer);
38 | }
39 |
40 | public writeString(str: string) {
41 | let stringBuffer = Buffer.from(str);
42 | this.writeInt32(stringBuffer.length);
43 | if (stringBuffer.length > 0) {
44 | this._socket.write(stringBuffer);
45 | }
46 | }
47 |
48 | public write(buffer: Buffer) {
49 | this._socket.write(buffer);
50 | }
51 |
52 | public clearErrors() {
53 | this._hasInsufficientDataForReading = false;
54 | }
55 |
56 | public beginTransaction() {
57 | this._isInTransaction = true;
58 | this._bytesRead = 0;
59 | this.clearErrors();
60 | }
61 |
62 | public endTransaction() {
63 | this._isInTransaction = false;
64 | this._buffer = this._buffer.slice(this._bytesRead);
65 | this._bytesRead = 0;
66 | this.clearErrors();
67 | }
68 |
69 | public rollBackTransaction() {
70 | this._isInTransaction = false;
71 | this._bytesRead = 0;
72 | this.clearErrors();
73 | }
74 |
75 | public toString(): string {
76 | return this._buffer.toString();
77 | }
78 |
79 | public append(additionalData: Buffer) {
80 | if (this._buffer.length === 0) {
81 | this._buffer = additionalData;
82 | return;
83 | }
84 | let newBuffer = Buffer.alloc(this._buffer.length + additionalData.length);
85 | this._buffer.copy(newBuffer);
86 | additionalData.copy(newBuffer, this._buffer.length);
87 | this._buffer = newBuffer;
88 | }
89 |
90 | private isSufficientDataAvailable(length: number): boolean {
91 | if (this._buffer.length < (this._bytesRead + length)) {
92 | this._hasInsufficientDataForReading = true;
93 | }
94 |
95 | return !this._hasInsufficientDataForReading;
96 | }
97 |
98 | public readByte(): number {
99 | if (!this.isSufficientDataAvailable(1)) {
100 | return null;
101 | }
102 |
103 | let value = this._buffer.slice(this._bytesRead, this._bytesRead + 1)[0];
104 | if (this._isInTransaction) {
105 | this._bytesRead++;
106 | } else {
107 | this._buffer = this._buffer.slice(1);
108 | }
109 | return value;
110 | }
111 |
112 | public readInt32(): number {
113 | return this.readInt64();
114 | }
115 |
116 | public readInt64(): number {
117 | if (!this.isSufficientDataAvailable(8)) {
118 | return null;
119 | }
120 |
121 | let buf = this._buffer.slice(this._bytesRead, this._bytesRead + 8);
122 |
123 | if (this._isInTransaction) {
124 | this._bytesRead += 8;
125 | } else {
126 | this._buffer = this._buffer.slice(8);
127 | }
128 |
129 | return uint64be.decode(buf);
130 | }
131 |
132 | public readString(): string {
133 | let byteRead = this.readByte();
134 | if (this._hasInsufficientDataForReading) {
135 | return null;
136 | }
137 |
138 | if (byteRead < 0) {
139 | throw new Error('IOException() - Socket.readString() failed to read string value');
140 | }
141 |
142 | let type = Buffer.from([byteRead]).toString();
143 | let isUnicode = false;
144 | switch (type) {
145 | case 'N':
146 | return null;
147 | case 'U':
148 | isUnicode = true;
149 | break;
150 | case 'A':
151 | isUnicode = false;
152 | break;
153 | default:
154 | throw new Error(`IOException() - Socket.readString() failed to parse unknown string type ${type}`);
155 | }
156 |
157 | let len = this.readInt32();
158 | if (this._hasInsufficientDataForReading) {
159 | return null;
160 | }
161 |
162 | if (!this.isSufficientDataAvailable(len)) {
163 | return null;
164 | }
165 |
166 | let stringBuffer = this._buffer.slice(this._bytesRead, this._bytesRead + len);
167 | if (this._isInTransaction) {
168 | this._bytesRead += len;
169 | } else {
170 | this._buffer = this._buffer.slice(len);
171 | }
172 |
173 | return isUnicode ? stringBuffer.toString() : stringBuffer.toString('ascii');
174 | }
175 |
176 | public readAsciiString(length: number): string {
177 | if (!this.isSufficientDataAvailable(length)) {
178 | return null;
179 | }
180 |
181 | let stringBuffer = this._buffer.slice(this._bytesRead, this._bytesRead + length);
182 | if (this._isInTransaction) {
183 | this._bytesRead += length;
184 | } else {
185 | this._buffer = this._buffer.slice(length);
186 | }
187 |
188 | return stringBuffer.toString('ascii');
189 | }
190 |
191 | private readValueInTransaction(dataType: DataType, length?: number): T {
192 | let startedTransaction = false;
193 | if (!this._isInTransaction) {
194 | this.beginTransaction();
195 | startedTransaction = true;
196 | }
197 | let data: any;
198 | switch (dataType) {
199 | case DataType.int32:
200 | data = this.readInt32();
201 | break;
202 | case DataType.int64:
203 | data = this.readInt64();
204 | break;
205 | case DataType.string:
206 | data = this.readString();
207 | break;
208 | case DataType.asciiString:
209 | data = this.readAsciiString(length!);
210 | break;
211 | }
212 |
213 | if (this._hasInsufficientDataForReading) {
214 | if (startedTransaction) {
215 | this.rollBackTransaction();
216 | }
217 | return undefined;
218 | }
219 |
220 | if (startedTransaction) {
221 | this.endTransaction();
222 | }
223 | return data;
224 | }
225 |
226 | public readInt32InTransaction(): number {
227 | return this.readValueInTransaction(DataType.int32);
228 | }
229 |
230 | public readInt64InTransaction(): number {
231 | return this.readValueInTransaction(DataType.int64);
232 | }
233 |
234 | public readStringInTransaction(): string {
235 | return this.readValueInTransaction(DataType.string);
236 | }
237 |
238 | public readAsciiStringInTransaction(length: number): string {
239 | return this.readValueInTransaction(DataType.asciiString, length);
240 | }
241 | }
242 |
243 | enum DataType {
244 | int32,
245 | int64,
246 | string,
247 | asciiString
248 | }
--------------------------------------------------------------------------------
/src/common/platform/pathUtils.ts:
--------------------------------------------------------------------------------
1 | import * as path from "path";
2 |
3 | export const IPathUtils = Symbol('IPathUtils');
4 |
5 | export interface IPathUtils {
6 | getPathVariableName(): 'Path' | 'PATH';
7 | basename(pathValue: string, ext?: string): string;
8 | }
9 |
10 | export class PathUtils implements IPathUtils {
11 | constructor(private _isWindows: boolean) { }
12 |
13 | public getPathVariableName() {
14 | return this._isWindows ? 'Path' : 'PATH';
15 | }
16 |
17 | public basename(pathValue: string, ext?: string): string {
18 | return path.basename(pathValue, ext);
19 | }
20 | }
--------------------------------------------------------------------------------
/src/debugger/common/contracts.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import * as net from "net";
4 |
5 | export interface IPythonProcess extends NodeJS.EventEmitter {
6 | connect(buffer: Buffer, socket: net.Socket): boolean;
7 | handleInComingData(buffer: Buffer);
8 | detach();
9 | kill();
10 | }
11 |
12 | export interface IDebugServer {
13 | port: number;
14 | host?: string;
15 | }
16 |
17 | export interface LaunchRequestArguments {
18 | pythonPath: string;
19 | port?: number;
20 | host?: string;
21 | }
--------------------------------------------------------------------------------
/src/debugger/common/utils.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import untildify = require("untildify");
4 | import * as path from "path";
5 | import * as child_process from "child_process";
6 | export const IS_WINDOWS = /^win/.test(process.platform);
7 |
8 | /**
9 | * 获取python可执行文件.
10 | *
11 | * @param {string} pythonPath
12 | * @returns {string}
13 | */
14 | export function getPythonExecutable(pythonPath: string): string {
15 | pythonPath = untildify(pythonPath);
16 |
17 | if (pythonPath === 'python' ||
18 | pythonPath.indexOf(path.sep) === -1 ||
19 | path.basename(pythonPath) === path.dirname(pythonPath)) {
20 | return pythonPath;
21 | }
22 |
23 | if (isValidPythonPath(pythonPath)) {
24 | return pythonPath;
25 | }
26 |
27 | const knownPythonExecutables = ['python', 'python3.7', 'python3.6', 'python3.5', 'python3', 'python2.7', 'python2'];
28 |
29 | for (let executableName of knownPythonExecutables) {
30 | // Suffix with 'python' for linux and 'osx', and 'python.exe' for 'windows'.
31 | if (IS_WINDOWS) {
32 | executableName = `${executableName}.exe`;
33 | if (isValidPythonPath(path.join(pythonPath, executableName))) {
34 | return path.join(pythonPath, executableName);
35 | }
36 | if (isValidPythonPath(path.join(pythonPath, 'scripts', executableName))) {
37 | return path.join(pythonPath, 'scripts', executableName);
38 | }
39 | } else {
40 | if (isValidPythonPath(path.join(pythonPath, executableName))) {
41 | return path.join(pythonPath, executableName);
42 | }
43 | if (isValidPythonPath(path.join(pythonPath, 'bin', executableName))) {
44 | return path.join(pythonPath, executableName);
45 | }
46 | }
47 | }
48 |
49 | return pythonPath;
50 | }
51 |
52 | /**
53 | * python可执行文件路径是否合法.
54 | *
55 | * @param {string} pythonPath
56 | * @returns {boolean}
57 | */
58 | function isValidPythonPath(pythonPath: string): boolean {
59 | try {
60 | const output = child_process.execFileSync(pythonPath, ['-c', 'print(1234)'], {encoding: 'utf8'});
61 | (output as string).startsWith('1234');
62 | } catch (e) {
63 | return false;
64 | }
65 | }
--------------------------------------------------------------------------------
/src/debugger/debugClients/baseDebugClient.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import {EventEmitter} from "events";
4 | import {IDebugServer, IPythonProcess} from "../common/contracts";
5 | import {BaseDebugServer} from "../debugServers/baseDebugServer";
6 |
7 | export abstract class BaseDebugClient extends EventEmitter {
8 | constructor(protected _args: T) {
9 | super();
10 | }
11 |
12 | public abstract createDebugServer(pythonProcess?: IPythonProcess): BaseDebugServer;
13 |
14 | public stop() { }
15 |
16 | public launchApplicationToDebug(debugServer: IDebugServer): Promise {
17 | return Promise.resolve();
18 | }
19 | }
--------------------------------------------------------------------------------
/src/debugger/debugClients/launcherProvider.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import * as path from "path";
4 |
5 | export interface IDebugLauncherScriptProvider {
6 | getLauncherFilePath(): string;
7 | }
8 |
9 | export class DebuggerLauncherScriptProvider implements IDebugLauncherScriptProvider {
10 | public getLauncherFilePath(): string {
11 | return path.join(path.dirname(__dirname), '..', '..', 'pythonFiles', 'pydev', 'launcher.py');
12 | }
13 | }
--------------------------------------------------------------------------------
/src/debugger/debugClients/localDebugClient.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import * as vscode from "vscode";
4 | import {BaseDebugClient} from "./baseDebugClient";
5 | import {IDebugServer, IPythonProcess, LaunchRequestArguments} from "../common/contracts";
6 | import {ChildProcess, spawn} from "child_process";
7 | import {BaseDebugServer} from "../debugServers/baseDebugServer";
8 | import {IDebugLauncherScriptProvider} from "./launcherProvider";
9 | import {LocalDebugServer} from "../debugServers/localDebugServer";
10 | import { isNotInstalledError } from "../../common/helpers";
11 | import { Logger } from "../../common/logger";
12 | import { PythonPreviewManager } from "../../features/previewManager";
13 |
14 | enum DebugServerStatus {
15 | Unknown = 1,
16 | Running = 2,
17 | NotRunning = 3
18 | }
19 |
20 | export class LocalDebugClient extends BaseDebugClient {
21 | protected _pyProc: ChildProcess | undefined;
22 | protected _pythonProcess!: IPythonProcess;
23 | protected _debugServer: BaseDebugServer | undefined;
24 |
25 | constructor(args: LaunchRequestArguments, private _launcherScriptProvider: IDebugLauncherScriptProvider, private _previewManager: PythonPreviewManager, private _logger: Logger) {
26 | super(args);
27 | }
28 |
29 | private get debugServerStatus(): DebugServerStatus {
30 | if (this._debugServer) {
31 | switch (this._debugServer!.isRunning) {
32 | case true:
33 | return DebugServerStatus.Running;
34 | case false:
35 | return DebugServerStatus.NotRunning;
36 | }
37 | }
38 | return DebugServerStatus.Unknown;
39 | }
40 |
41 | public createDebugServer(pythonProcess?: IPythonProcess): BaseDebugServer {
42 | this._pythonProcess = pythonProcess!;
43 | this._debugServer = new LocalDebugServer(this._pythonProcess!, this._args, this._logger);
44 | return this._debugServer;
45 | }
46 |
47 | public stop() {
48 | if (this._debugServer) {
49 | this._debugServer!.stop();
50 | this._debugServer = undefined;
51 | }
52 | if (this._pyProc) {
53 | this._pyProc.kill();
54 | this._pyProc = undefined;
55 | }
56 | }
57 |
58 | private displayError(error: any) {
59 | let errorMsg = typeof error === 'string' ? error : ((error.message && error.message.length > 0) ? error.message : '');
60 | if (isNotInstalledError(error)) {
61 | errorMsg = `Failed to launch the Python Process, please validate the path '${this._args.pythonPath}'`;
62 | }
63 | if (errorMsg.length > 0) {
64 | vscode.window.showErrorMessage(errorMsg);
65 | this._logger.error(errorMsg);
66 | }
67 | }
68 |
69 | public async launchApplicationToDebug(debugServer: IDebugServer): Promise {
70 | return new Promise((resolve, reject) => {
71 | let pythonPath = 'python';
72 | if (typeof this._args.pythonPath === 'string' && this._args.pythonPath.trim().length > 0) {
73 | pythonPath = this._args.pythonPath;
74 | }
75 | const args = this.buildLaunchArguments(debugServer.port);
76 | this._logger.info('Starting Debug Client');
77 | this._pyProc = spawn(pythonPath, args);
78 | this.handleProcessOutput(this._pyProc!, reject);
79 |
80 | // Here we wait for the application to connect to the socket server.
81 | // Only once connected do we know that the application has successfully launched.
82 | this._debugServer!.debugClientConnected
83 | .then(resolve)
84 | .catch(ex => console.error('Python Client Connect Exception: _debugServer.debugClientConnected', ex));
85 | })
86 | }
87 |
88 | protected handleProcessOutput(proc: ChildProcess, failedToLaunch: (error: Error | string | Buffer) => void) {
89 | proc.on('error', error => {
90 | const status = this.debugServerStatus;
91 | if (status === DebugServerStatus.Running) {
92 | return;
93 | }
94 | if (status === DebugServerStatus.NotRunning && typeof(error) === 'object' && error !== null) {
95 | return failedToLaunch(error);
96 | }
97 | // This could happen when the debugger didn't launch at all, e.g. python doesn't exist.
98 | this.displayError(error);
99 | this._previewManager.dispose();
100 | });
101 |
102 | proc.stderr.setEncoding('utf8');
103 | proc.stderr.on('data', error => {
104 | // if (this.debugServerStatus === DebugServerStatus.NotRunning) {
105 | // return failedToLaunch(error);
106 | // }
107 | let x = 0;
108 | });
109 |
110 | proc.stdout.setEncoding('utf-8');
111 | proc.stdout.on('data', d => {
112 | const arr = d.toString().split('&');
113 | const length = arr.length;
114 | if (length <= 2) return;
115 | const dataType = arr[length - 2];
116 | const dataMessage = arr[length - 1];
117 | if (dataType === 'info') {
118 | this._logger.info(dataMessage);
119 | } else if (dataType === 'warn') {
120 | this._logger.warn(dataMessage);
121 | } else if (dataType === 'error') {
122 | this.displayError(dataMessage);
123 | this._previewManager.dispose();
124 | }
125 | });
126 | }
127 |
128 | private buildLaunchArguments(debugPort: number): string[] {
129 | return [...this.buildDebugArguments(debugPort)];
130 | }
131 |
132 | private buildDebugArguments(debugPort: number): string[] {
133 | const launcherFilePath = this._launcherScriptProvider.getLauncherFilePath();
134 | return [launcherFilePath, debugPort.toString(), 'ba648ec3-d025-44bb-92fb-7ded4267a243'];
135 | }
136 | }
--------------------------------------------------------------------------------
/src/debugger/debugServers/baseDebugServer.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import {EventEmitter} from "events";
4 | import {createDeferred, Deferred} from "../../common/helpers";
5 | import {Socket} from "net";
6 | import {IDebugServer, IPythonProcess} from "../common/contracts";
7 |
8 | export abstract class BaseDebugServer extends EventEmitter {
9 | protected _clientSocket: Deferred;
10 | protected _pythonProcess:IPythonProcess;
11 | protected _isRunning: boolean;
12 | protected _debugClientConnected: Deferred;
13 |
14 | constructor(pythonProcess?: IPythonProcess) {
15 | super();
16 | this._pythonProcess = pythonProcess;
17 | this._debugClientConnected = createDeferred();
18 | this._clientSocket = createDeferred();
19 | }
20 |
21 | public get isRunning(): boolean {
22 | return this._isRunning;
23 | }
24 |
25 | public get debugClientConnected(): Promise {
26 | return this._debugClientConnected.promise;
27 | }
28 |
29 | public abstract start(): Promise;
30 |
31 | public abstract stop();
32 | }
--------------------------------------------------------------------------------
/src/debugger/debugServers/localDebugServer.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import * as vscode from 'vscode';
4 | import {BaseDebugServer} from "./baseDebugServer";
5 | import * as net from "net";
6 | import {IDebugServer, IPythonProcess, LaunchRequestArguments} from "../common/contracts";
7 | import { Logger } from '../../common/logger';
8 |
9 | export class LocalDebugServer extends BaseDebugServer {
10 | private _debugSocketServer: net.Server | undefined;
11 |
12 | constructor(pythonProcess: IPythonProcess | undefined, private _args: LaunchRequestArguments, private _logger: Logger) {
13 | super(pythonProcess);
14 | }
15 |
16 | public stop() {
17 | if (!this._debugSocketServer) {
18 | return;
19 | }
20 |
21 | try {
22 | this._debugSocketServer.close();
23 | } catch { }
24 |
25 | this._debugSocketServer = undefined;
26 | }
27 |
28 | public async start(): Promise {
29 | return new Promise((resolve, reject) => {
30 | let connectedResolve = this._debugClientConnected.resolve.bind(this._debugClientConnected);
31 | let connected = false;
32 | let disconnected = false;
33 | this._debugSocketServer = net.createServer(c => {
34 | // "connection"监听器
35 | c.on('data', (buffer: Buffer) => {
36 | if (connectedResolve) {
37 | // debug客户端已经连接到debug服务器
38 | connectedResolve(true);
39 | this._logger.info('Debug Client Connected');
40 | connectedResolve = null;
41 | }
42 | if (!connected) {
43 | connected = this._pythonProcess.connect(buffer, c);
44 | } else {
45 | this._pythonProcess.handleInComingData(buffer);
46 | this._isRunning = true;
47 | }
48 | });
49 | c.on('close', d => {
50 | disconnected = true;
51 | this.emit('detach', d);
52 | });
53 | c.on('timeout', () => {
54 | const msg = `Debugger client timeout.`;
55 | this._logger.warn(msg);
56 | });
57 | c.on('error', ex => {
58 | if (connected || disconnected) {
59 | return;
60 | }
61 | const msg = `There was an error in starting the debug server. Error = ${JSON.stringify(ex)}`;
62 | reject(msg);
63 | });
64 | });
65 |
66 | this._debugSocketServer!.on('error', ex => {
67 | const exMsg = JSON.stringify(ex);
68 | let msg = '';
69 | if ((ex as any).code === 'EADDRINUSE') {
70 | msg = `The port used for debugging is in use, please try again or try restarting Visual Studio Code, Error = ${exMsg}`;
71 | } else {
72 | if (connected) {
73 | return;
74 | }
75 | msg = `There was an error in starting the debug server. Error = ${exMsg}`;
76 | }
77 | reject(msg);
78 | });
79 |
80 | const port = typeof this._args.port === 'number' ? this._args.port! : 0;
81 | const host = typeof this._args.host === 'string' && this._args.host!.trim().length > 0 ? this._args.host!.trim() : 'localhost';
82 | this._debugSocketServer!.listen({port: port, host: host}, () => {
83 | const server = this._debugSocketServer!.address();
84 | resolve({port: server.port});
85 | })
86 | });
87 | }
88 | }
--------------------------------------------------------------------------------
/src/debugger/proxyCommands.ts:
--------------------------------------------------------------------------------
1 | export class Commands {
2 | public static OutputCommandBytes: Buffer = Buffer.from('outp');
3 | public static DetachCommandBytes: Buffer = Buffer.from('detc');
4 | }
--------------------------------------------------------------------------------
/src/debugger/pythonProcess.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import {EventEmitter} from "events";
4 | import {IPythonProcess} from "./common/contracts";
5 | import {PythonProcessCallbackHandler} from "./pythonProcessCallbackHandler";
6 | import {SocketStream} from "../common/net/socket/socketStream";
7 | import * as net from "net";
8 | import { Commands } from "./proxyCommands";
9 |
10 | export class PythonProcess extends EventEmitter implements IPythonProcess {
11 | private _id: number;
12 | private _guid: string;
13 | private _callbackHandler: PythonProcessCallbackHandler;
14 | private _stream: SocketStream;
15 | private _guidRead: boolean;
16 | private _statusRead: boolean;
17 | private _pidRead: boolean;
18 | private _pid: number;
19 |
20 | constructor(id: number, guid: string) {
21 | super();
22 | this._id = id;
23 | this._guid = guid;
24 | }
25 |
26 | public kill() {
27 | if (this._pid && typeof this._pid === 'number') {
28 | try {
29 | let kill = require('tree-kill');
30 | kill(this._pid!);
31 | this._pid = undefined;
32 | } catch (e) {
33 | }
34 |
35 | }
36 | }
37 |
38 | public detach() {
39 | this._stream.write(Buffer.from('detc'));
40 | }
41 |
42 | public connect(buffer: Buffer, socket: net.Socket): boolean {
43 | if (!this._stream) {
44 | this._stream = new SocketStream(socket, buffer);
45 | } else {
46 | this._stream.append(buffer);
47 | }
48 |
49 | if (!this._guidRead) {
50 | this._stream.beginTransaction();
51 | this._stream.readString();
52 | if (this._stream.hasInsufficientDataForReading) {
53 | this._stream.rollBackTransaction();
54 | return false;
55 | }
56 | this._guidRead = true;
57 | this._stream.endTransaction();
58 | }
59 |
60 | if (!this._statusRead) {
61 | this._stream.beginTransaction();
62 | this._stream.readInt32();
63 | if (this._stream.hasInsufficientDataForReading) {
64 | this._stream.rollBackTransaction();
65 | return false;
66 | }
67 | this._statusRead = true;
68 | this._stream.endTransaction();
69 | }
70 |
71 | if (!this._pidRead) {
72 | this._stream.beginTransaction();
73 | this._pid = this._stream.readInt32();
74 | if (this._stream.hasInsufficientDataForReading) {
75 | this._stream.rollBackTransaction();
76 | return false;
77 | }
78 | this._pidRead = true;
79 | this._stream.endTransaction();
80 | }
81 |
82 | this._callbackHandler = new PythonProcessCallbackHandler(this, this._stream);
83 | this._callbackHandler.on('processLoaded', pythonVersion => this.emit('processLoaded', pythonVersion));
84 | this._callbackHandler.on('output', (fileName, output) => this.emit('output', fileName, output));
85 | this._callbackHandler.on('detach', () => this.emit('detach'));
86 | this._callbackHandler.handleIncomingData();
87 | return true;
88 | }
89 |
90 | public handleInComingData(buffer: Buffer) {
91 | this._stream.append(buffer);
92 |
93 | if (!this._guidRead) {
94 | this._stream.rollBackTransaction();
95 | this._stream.readString();
96 | if (this._stream.hasInsufficientDataForReading) {
97 | return;
98 | }
99 | this._guidRead = true;
100 | this._stream.endTransaction();
101 | }
102 |
103 | if (!this._statusRead) {
104 | this._stream.beginTransaction();
105 | this._stream.readInt32();
106 | if (this._stream.hasInsufficientDataForReading) {
107 | this._stream.rollBackTransaction();
108 | return;
109 | }
110 | this._pidRead = true;
111 | this._stream.endTransaction();
112 | }
113 |
114 | this._callbackHandler.handleIncomingData();
115 | }
116 |
117 | public sendExecutableText(folder: string, fileName: string, code: string, cumulativeModde: boolean, allowAllModules: boolean, maxExecutedLines: number) {
118 | this._stream.write(Commands.OutputCommandBytes);
119 | if (cumulativeModde) {
120 | this._stream.writeInt64(1);
121 | } else {
122 | this._stream.writeInt64(0);
123 | }
124 | if (allowAllModules) {
125 | this._stream.writeInt64(1);
126 | } else {
127 | this._stream.writeInt64(0);
128 | }
129 | this._stream.writeInt64(maxExecutedLines);
130 | this._stream.writeString(folder);
131 | this._stream.writeString(fileName);
132 | this._stream.writeString(code);
133 | }
134 | }
--------------------------------------------------------------------------------
/src/debugger/pythonProcessCallbackHandler.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import {EventEmitter} from "events";
4 | import {IPythonProcess} from "./common/contracts";
5 | import {SocketStream} from "../common/net/socket/socketStream";
6 |
7 | export class PythonProcessCallbackHandler extends EventEmitter {
8 | private _pythonProcess: IPythonProcess;
9 | private _stream: SocketStream;
10 |
11 | constructor(pythonProcess: IPythonProcess, stream: SocketStream) {
12 | super();
13 | this._pythonProcess = pythonProcess;
14 | this._stream =stream;
15 | }
16 |
17 | public handleIncomingData() {
18 | if (this._stream.length === 0) {
19 | return;
20 | }
21 |
22 | this._stream.beginTransaction();
23 |
24 | let cmd = this._stream.readAsciiString(4);
25 | if (this._stream.hasInsufficientDataForReading) {
26 | return;
27 | }
28 |
29 | switch (cmd) {
30 | case 'LOAD': this.handleProcessLoad(); break;
31 | case 'OUTP': this.handleDebuggerOutput(); break;
32 | case 'DETC': this.handleDetach(); break;
33 | default:
34 | this.emit('error', `Unhandled command '${cmd}'`);
35 | }
36 |
37 | if (this._stream.hasInsufficientDataForReading) {
38 | this._stream.rollBackTransaction();
39 | return;
40 | }
41 |
42 | this._stream.endTransaction();
43 | if (this._stream.length > 0) {
44 | this.handleIncomingData();
45 | }
46 | }
47 |
48 | private handleProcessLoad() {
49 | let pythonVersion = this._stream.readString();
50 | if (this._stream.hasInsufficientDataForReading) {
51 | return;
52 | }
53 | this.emit('processLoaded', pythonVersion);
54 | }
55 |
56 | private handleDebuggerOutput() {
57 | let fileName = this._stream.readString();
58 | let output = this._stream.readString();
59 | if (this._stream.hasInsufficientDataForReading) {
60 | return;
61 | }
62 | this.emit("output", fileName, output);
63 | }
64 |
65 | private handleDetach() {
66 | this.emit('detach');
67 | }
68 | }
--------------------------------------------------------------------------------
/src/extension.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import { Logger } from './common/logger';
3 | import { PythonContentProvider } from './features/previewContentProvider';
4 | import { PythonPreviewManager } from './features/previewManager';
5 | import { CommandManager } from './common/commandManager';
6 | import * as commands from './commands';
7 |
8 | export function activate(context: vscode.ExtensionContext) {
9 | const logger = new Logger();
10 |
11 | const contentProvider = new PythonContentProvider(context, logger);
12 | const previewManager = new PythonPreviewManager(context, contentProvider, logger);
13 | context.subscriptions.push(previewManager);
14 |
15 | const commandManager = new CommandManager();
16 | context.subscriptions.push(commandManager);
17 | commandManager.register(new commands.ShowPreviewCommand(previewManager));
18 | commandManager.register(new commands.ShowPreviewToSideCommand(previewManager));
19 | commandManager.register(new commands.ShowLockedPreviewToSideCommand(previewManager));
20 | commandManager.register(new commands.ShowSourceCommand(previewManager));
21 | commandManager.register(new commands.RefreshPreviewCommand(previewManager));
22 | commandManager.register(new commands.ToggleLockCommand(previewManager));
23 |
24 | context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(() => {
25 | logger.updateConfiguration();
26 | previewManager.updateConfiguration();
27 | }))
28 | }
--------------------------------------------------------------------------------
/src/features/preview.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 | import * as path from "path";
3 |
4 | import {PythonContentProvider} from "./previewContentProvider";
5 | import {PythonPreviewConfigurationManager} from "./previewConfig";
6 | import {Logger} from "../common/logger";
7 | import {disposeAll} from "../common/dispose";
8 | import { PythonPreviewManager } from './previewManager';
9 | import { isPythonFile } from '../common/file';
10 | import { PythonOutput, PythonOutputStatus } from './pythonOutput';
11 |
12 | export interface PreviewState {
13 | readonly resource: string;
14 | readonly locked: boolean;
15 | readonly startingInstruction: number
16 | readonly width: number;
17 | }
18 |
19 | export class PythonPreview {
20 | public static viewtype = 'pythonPreview';
21 |
22 | private _resource: vscode.Uri;
23 | private _locked: boolean;
24 | private _startingInstrcution: number | undefined;
25 |
26 | private _codAndNavWidth: number | undefined;
27 |
28 | private readonly _webviewPanel: vscode.WebviewPanel;
29 | private readonly _disposables: vscode.Disposable[] = [];
30 | private _currentVersion?: { resource: vscode.Uri, version: number };
31 | private _disposed: boolean = false;
32 | private readonly _onDidDisposeEmitter = new vscode.EventEmitter();
33 | public readonly onDidDispose = this._onDidDisposeEmitter.event;
34 |
35 | private readonly _onDidChangeViewStateEmitter = new vscode.EventEmitter();
36 | public readonly onDidChangeViewState = this._onDidChangeViewStateEmitter.event;
37 |
38 |
39 |
40 | // 反序列化时使用
41 | public static async receive(webviewPanel: vscode.WebviewPanel,
42 | state: PreviewState,
43 | previewManager: PythonPreviewManager,
44 | context: vscode.ExtensionContext,
45 | cachedOutputs: Map,
46 | contentProvider: PythonContentProvider,
47 | previewConfigurationManager: PythonPreviewConfigurationManager,
48 | logger: Logger): Promise {
49 | const resource = vscode.Uri.parse(state.resource);
50 | const locked = state.locked;
51 | const startingInstruction = state.startingInstruction;
52 | const width = state.width;
53 |
54 | const preview = new PythonPreview(webviewPanel,
55 | resource,
56 | locked,
57 | startingInstruction,
58 | width,
59 | previewManager,
60 | context,
61 | cachedOutputs,
62 | contentProvider,
63 | previewConfigurationManager,
64 | logger);
65 |
66 | await preview.doUpdate();
67 | return preview;
68 | }
69 |
70 | public static create(resource: vscode.Uri,
71 | previewColumn: vscode.ViewColumn,
72 | locked: boolean,
73 | previewManager: PythonPreviewManager,
74 | context: vscode.ExtensionContext,
75 | cachedOutputs: Map,
76 | contentProvider: PythonContentProvider,
77 | previewConfigurationManager: PythonPreviewConfigurationManager,
78 | logger: Logger): PythonPreview {
79 | const webviewPanel = vscode.window.createWebviewPanel(PythonPreview.viewtype,
80 | PythonPreview.getPreviewTitle(resource, locked),
81 | previewColumn,
82 | {
83 | enableFindWidget: true,
84 | ...PythonPreview.getWebviewOptions(resource, context)
85 | });
86 | return new PythonPreview(webviewPanel,
87 | resource,
88 | locked,
89 | undefined,
90 | undefined,
91 | previewManager,
92 | context,
93 | cachedOutputs,
94 | contentProvider,
95 | previewConfigurationManager,
96 | logger);
97 | }
98 |
99 | private constructor(webviewPanel: vscode.WebviewPanel,
100 | resource: vscode.Uri,
101 | locked: boolean,
102 | staringInstruction: number | undefined,
103 | width: number | undefined,
104 | private readonly _previewManager: PythonPreviewManager,
105 | private readonly _context: vscode.ExtensionContext,
106 | private readonly _cachedOutputs: Map,
107 | private readonly _contentProvider: PythonContentProvider,
108 | private readonly _previewConfigurationManager: PythonPreviewConfigurationManager,
109 | private readonly _logger: Logger) {
110 | this._resource = resource;
111 | this._locked = locked;
112 | this._startingInstrcution = staringInstruction;
113 | this._codAndNavWidth = width;
114 | this._webviewPanel = webviewPanel;
115 |
116 | this._webviewPanel.onDidDispose(() => {
117 | this.dispose();
118 | }, null, this._disposables);
119 |
120 | this._webviewPanel.onDidChangeViewState(e => {
121 | this.updateContentWithStatus(true);
122 | this._onDidChangeViewStateEmitter.fire(e);
123 | }, null, this._disposables);
124 |
125 | // 处理来自webview的消息
126 | this._webviewPanel.webview.onDidReceiveMessage(e => {
127 | if (e.source !== this._resource.toString()) {
128 | return;
129 | }
130 |
131 | switch (e.type) {
132 | case 'command':
133 | vscode.commands.executeCommand(e.body.command, ...e.body.args);
134 | break;
135 | case 'updateStartingInstruction':
136 | this.onDidUpdateStartingInstruction(e.body.curInstr);
137 | break;
138 | case 'updateCodAndNavWidth':
139 | this.onDidUpdataCodAndNavWidth(e.body.width);
140 | break;
141 | }
142 | }, null, this._disposables);
143 |
144 | vscode.workspace.onDidChangeTextDocument(event => {
145 | if (this.isPreviewOf(event.document.uri)) {
146 | // 文本改变直接传送给调试器,等待调试器返回trace
147 | this._previewManager.postMessageToDebugger(event.document.fileName, event.document.getText());
148 | }
149 | }, null, this._disposables);
150 |
151 | vscode.window.onDidChangeActiveTextEditor(editor => {
152 | if (editor && isPythonFile(editor.document) && !this._locked) {
153 | this.update(editor.document.uri);
154 | }
155 | }, null, this._disposables);
156 | }
157 |
158 | public get resource(): vscode.Uri {
159 | return this._resource;
160 | }
161 |
162 | public get locked(): boolean {
163 | return this._locked;
164 | }
165 |
166 | public get state(): PreviewState {
167 | return {
168 | resource: this._resource.toString(),
169 | locked: this._locked,
170 | startingInstruction: this._startingInstrcution,
171 | width: this._codAndNavWidth
172 | };
173 | }
174 |
175 | public get visibale(): boolean {
176 | return this._webviewPanel.visible;
177 | }
178 |
179 | public get position(): vscode.ViewColumn | undefined {
180 | return this._webviewPanel.viewColumn;
181 | }
182 |
183 | public get disposed(): boolean {
184 | return this._disposed;
185 | }
186 |
187 | public dispose() {
188 | if (this._disposed) {
189 | return;
190 | }
191 |
192 | this._disposed = true;
193 | this._onDidDisposeEmitter.fire();
194 |
195 | this._onDidDisposeEmitter.dispose();
196 | this._onDidChangeViewStateEmitter.dispose();
197 | this._webviewPanel.dispose();
198 |
199 | disposeAll(this._disposables);
200 |
201 | }
202 |
203 | public updateConfiguration() {
204 | if (this._previewConfigurationManager.hasConfigurationChanged(this._resource)) {
205 | this.initialContent();
206 | }
207 | }
208 |
209 | public update(resource: vscode.Uri) {
210 | const isResourceChange = resource.fsPath !== this._resource.fsPath;
211 | if (isResourceChange) {
212 | this._resource = resource;
213 | this._startingInstrcution = undefined;
214 | this.initialContent();
215 | }
216 | }
217 |
218 | public async doUpdate(): Promise {
219 | const document = await vscode.workspace.openTextDocument(this._resource);
220 | this._currentVersion = { resource: this._resource, version: document.version };
221 | this._webviewPanel.title = PythonPreview.getPreviewTitle(this._resource, this._locked);
222 | this._webviewPanel.webview.options = PythonPreview.getWebviewOptions(this._resource, this._context);
223 | this._webviewPanel.webview.html = this._contentProvider.provideTextDocumentContent(document, this._previewConfigurationManager, this.state);
224 | this._previewManager.postMessageToDebugger(document.fileName, document.getText());
225 | }
226 |
227 | public async initialContent(): Promise {
228 | const document = await vscode.workspace.openTextDocument(this._resource);
229 |
230 | this._webviewPanel.title = PythonPreview.getPreviewTitle(this._resource, this._locked);
231 | this._webviewPanel.webview.options = PythonPreview.getWebviewOptions(this._resource, this._context);
232 | this._webviewPanel.webview.html = this._contentProvider.provideTextDocumentContent(document, this._previewConfigurationManager, this.state);
233 |
234 | this._previewManager.postMessageToDebugger(document.fileName, document.getText());
235 | }
236 |
237 | public async updateContent(): Promise {
238 | const document = await vscode.workspace.openTextDocument(this._resource);
239 | if (this._currentVersion && this._resource.fsPath === this._currentVersion.resource.fsPath && document.version === this._currentVersion.version) {
240 | this.updateContentWithStatus(true);
241 | } else {
242 | this.updateContentWithStatus(false);
243 | }
244 | this._currentVersion = { resource: this._resource, version: document.version };
245 | }
246 |
247 | public updateStatus() {
248 | this._startingInstrcution = undefined;
249 | }
250 |
251 | public updateContentWithStatus(hasStatus: boolean) {
252 | const cacheOutput = this._cachedOutputs.get(this._resource.fsPath);
253 | // 如果此时还没有缓存的输出或者正在调试中,则直接返回
254 | if (!cacheOutput || cacheOutput.status !== PythonOutputStatus.Prcoessed) return;
255 | const config = this._previewConfigurationManager.getConfigCacheForResource(this._resource);
256 | if (this._codAndNavWidth === undefined) {
257 | this._codAndNavWidth = config.contentConfig.codAndNavWidth;
258 | }
259 | const options = {
260 | jumpToEnd: true,
261 | startingInstruction: undefined,
262 | disableHeapNesting: config.contentConfig.disableHeapNesting,
263 | textualMemoryLabels: config.contentConfig.textualMemoryLabels,
264 | compactFuncLabels: config.contentConfig.compactFuncLabels,
265 | showAllFrameLabels: config.contentConfig.showAllFrameLabels,
266 | hideCode: config.contentConfig.hideCode,
267 | lang: this._previewManager.lang,
268 | width: this._codAndNavWidth
269 | };
270 | if (hasStatus) options.startingInstruction = this._startingInstrcution;
271 | if (this.position) {
272 | this._logger.info(`Updating ${PythonPreview.getPreviewTitle(this._resource, this._locked)} (Group ${this.position})`);
273 | } else {
274 | this._logger.info(`Updating ${PythonPreview.getPreviewTitle(this._resource, this._locked)}`);
275 | }
276 | this.postMessage({
277 | type: 'updateContent',
278 | data: cacheOutput.trace,
279 | options: options
280 | });
281 | }
282 |
283 | public matchesResource(otherResource: vscode.Uri,
284 | otherPosition: vscode.ViewColumn | undefined,
285 | otherLocked: boolean): boolean {
286 | if (this.position !== otherPosition) {
287 | return false;
288 | }
289 |
290 | if (this._locked !== otherLocked) {
291 | return false;
292 | }
293 |
294 | return this.isPreviewOf(otherResource);
295 | }
296 |
297 | public matches(otherPreview: PythonPreview): boolean {
298 | return this.matchesResource(otherPreview._resource, otherPreview.position, otherPreview._locked);
299 | }
300 |
301 | public reveal(viewColumn: vscode.ViewColumn) {
302 | this._webviewPanel.reveal(viewColumn);
303 | }
304 |
305 | public toggleLock() {
306 | this._locked = !this._locked;
307 | this._webviewPanel.title = PythonPreview.getPreviewTitle(this._resource, this._locked);
308 | this.postMessage({
309 | type: 'updateLock',
310 | locked: this._locked
311 | });
312 | }
313 |
314 | public isPreviewOf(resource: vscode.Uri): boolean {
315 | return this._resource.fsPath === resource.fsPath;
316 | }
317 |
318 | public static getPreviewTitle(resource: vscode.Uri, locked: boolean): string {
319 | return locked
320 | ? `[Preview] ${path.basename(resource.fsPath)}`
321 | : `Preview ${path.basename(resource.fsPath)}`;
322 | }
323 |
324 | private postMessage(msg: any) {
325 | if (!this._disposed) {
326 | this._webviewPanel.webview.postMessage(msg);
327 | }
328 | }
329 |
330 | private static getWebviewOptions(resource: vscode.Uri, context: vscode.ExtensionContext): vscode.WebviewOptions {
331 | return {
332 | enableScripts: true,
333 | enableCommandUris: true,
334 | localResourceRoots: PythonPreview.getLocalResourceRoots(resource, context)
335 | };
336 | }
337 |
338 | private static getLocalResourceRoots(resource: vscode.Uri, context: vscode.ExtensionContext): vscode.Uri[] {
339 | const baseRoots = [vscode.Uri.file(context.extensionPath)];
340 |
341 | const folder = vscode.workspace.getWorkspaceFolder(resource);
342 | folder && baseRoots.push(folder.uri);
343 |
344 | (!resource.scheme || resource.scheme === 'file') && baseRoots.push(vscode.Uri.file(path.dirname(resource.fsPath)));
345 |
346 | return baseRoots;
347 | }
348 |
349 | private onDidUpdateStartingInstruction(curInstr: number) {
350 | this._startingInstrcution = curInstr;
351 | }
352 |
353 | private onDidUpdataCodAndNavWidth(width: number) {
354 | this._codAndNavWidth = width;
355 | }
356 | }
--------------------------------------------------------------------------------
/src/features/previewConfig.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from 'vscode';
2 |
3 |
4 | enum ReloadType {
5 | ReloadStyle = 1,
6 |
7 | ReloadContent = 2,
8 |
9 | ReloadTrace = 3
10 | }
11 |
12 | class StyleConfiguration {
13 | [key: string]: any;
14 | public readonly fontFamily: string | undefined;
15 | public readonly fontSize: number;
16 | public readonly langDisplayFF: string | undefined;
17 | public readonly langDisplayFS: number;
18 | public readonly codeFF: string | undefined;
19 | public readonly codeFS: number;
20 | public readonly codeLH: number;
21 | public readonly legendFF: string | undefined;
22 | public readonly legendFS: number;
23 | public readonly codeFooterDocsFF: string | undefined;
24 | public readonly codeFooterDocsFS: number;
25 | public readonly printOutputDocsFF: string | undefined;
26 | public readonly printOutputDocsFS: number;
27 | public readonly pyStdoutFF: string | undefined;
28 | public readonly pyStdoutFs: number;
29 | public readonly stackAndHeapHeaderFF: string | undefined;
30 | public readonly stackAndHeapHeaderFS: number;
31 | public readonly stackFrameFF: string | undefined;
32 | public readonly stackFrameFS: number;
33 | public readonly retValFS: number;
34 | public readonly stackFrameHeaderFF: string | undefined;
35 | public readonly stackFrameHeaderFS: number;
36 | public readonly heapObjectFF: string | undefined;
37 | public readonly heapObjectFS: number;
38 | public readonly typeLabelFF: string | undefined;
39 | public readonly typeLabelFS: number;
40 | public readonly light_highlightedArrow_color: string;
41 | public readonly light_highlightedStackFrame_bgColor: string;
42 | public readonly light_list_tuple_setTbl_bgColor: string;
43 | public readonly light_dict_class_instKey_bgColor: string;
44 | public readonly light_dict_class_instVal_bgColor: string;
45 | public readonly dark_highlightedArrow_color: string;
46 | public readonly dark_highlightedStackFrame_bgColor: string;
47 | public readonly dark_list_tuple_setTbl_bgColor: string;
48 | public readonly dark_dict_class_instKey_bgColor: string;
49 | public readonly dark_dict_class_instVal_bgColor: string;
50 | public readonly highContrast_highlightedArrow_color: string;
51 | public readonly highContrast_highlightedStackFrame_bgColor: string;
52 | public readonly highContrast_list_tuple_setTbl_bgColor: string;
53 | public readonly highContrast_dict_class_instKey_bgColor: string;
54 | public readonly highContrast_dict_class_instVal_bgColor: string;
55 | public readonly styles: string[];
56 |
57 | public constructor(pythonConfig: vscode.WorkspaceConfiguration) {
58 | this.fontFamily = pythonConfig.get('fontFamliy', undefined);
59 | this.fontSize = Math.max(16, +pythonConfig.get('fontSize', NaN));
60 | this.langDisplayFF = pythonConfig.get('langDisplay.fontFamily', undefined);
61 | this.langDisplayFS = Math.max(14, +pythonConfig.get('langDisplay.fontSize', NaN));
62 | this.codeFF = pythonConfig.get('code.fontFamily', undefined);
63 | this.codeFS = Math.max(15, +pythonConfig.get('code.fontSize', NaN));
64 | this.codeLH = Math.max(1, +pythonConfig.get('code.lineHeight', NaN));
65 | this.legendFF = pythonConfig.get('legend.fontFamily', undefined);
66 | this.legendFS = Math.max(12, +pythonConfig.get('legend.fontSize', NaN));
67 | this.codeFooterDocsFF = pythonConfig.get('codeFooterDocs.fontFamily', undefined);
68 | this.codeFooterDocsFS = Math.max(12, +pythonConfig.get('codeFooterDocs.fontSize', NaN));
69 | this.printOutputDocsFF = pythonConfig.get('printOutputDocs.fontFamily', undefined);
70 | this.printOutputDocsFS = Math.max(12, +pythonConfig.get('printOutputDocs.fontSize', NaN));
71 | this.pyStdoutFF = pythonConfig.get('progOutputs.fontFamily', undefined);
72 | this.pyStdoutFs = Math.max(14, +pythonConfig.get('progOutputs.fontSize', NaN));
73 | this.stackAndHeapHeaderFF = pythonConfig.get('stackAndHeapHeader.fontFamily', undefined);
74 | this.stackAndHeapHeaderFS = Math.max(14, +pythonConfig.get('stackAndHeapHeader.fontSize', NaN));
75 | this.stackFrameFF = pythonConfig.get('stackFrame.fontFamily', undefined);
76 | this.stackFrameFS = Math.max(14, +pythonConfig.get('stackFrame.fontSize', NaN));
77 | this.retValFS = Math.max(12, +pythonConfig.get('retVal.fontSize', NaN));
78 | this.stackFrameHeaderFF = pythonConfig.get('stackFrameHeder.fontFamily', undefined);;
79 | this.stackFrameHeaderFS = Math.max(14, +pythonConfig.get('stackFrameHeader.fontSize', NaN));
80 | this.heapObjectFF = pythonConfig.get('heapObject.fontFamily', undefined);
81 | this.heapObjectFS = Math.max(14, +pythonConfig.get('heapObject.fontSize', NaN));
82 | this.typeLabelFF = pythonConfig.get('typeLabel.fontFamily', undefined);
83 | this.typeLabelFS = Math.max(12, +pythonConfig.get('typeLabel.fontSize', NaN));
84 |
85 | this.light_highlightedArrow_color = pythonConfig.get('light.highlightedArrow.color');
86 | this.light_highlightedStackFrame_bgColor = pythonConfig.get('light.highlightedStackFrame.bgColor');
87 | this.light_list_tuple_setTbl_bgColor = pythonConfig.get('light.list-tuple-setTbl.bgColor');
88 | this.light_dict_class_instKey_bgColor = pythonConfig.get('light.dict-class-instKey.bgColor');
89 | this.light_dict_class_instVal_bgColor = pythonConfig.get('light.dict-class-instVal.bgColor');
90 |
91 | this.dark_highlightedArrow_color = pythonConfig.get('dark.highlightedArrow.color');
92 | this.dark_highlightedStackFrame_bgColor = pythonConfig.get('dark.highlightedStackFrame.bgColor');
93 | this.dark_list_tuple_setTbl_bgColor = pythonConfig.get('dark.list-tuple-setTbl.bgColor');
94 | this.dark_dict_class_instKey_bgColor = pythonConfig.get('dark.dict-class-instKey.bgColor');
95 | this.dark_dict_class_instVal_bgColor = pythonConfig.get('dark.dict-class-instVal.bgColor');
96 |
97 | this.highContrast_highlightedArrow_color = pythonConfig.get('high-contrast.highlightedArrow.color');
98 | this.highContrast_highlightedStackFrame_bgColor = pythonConfig.get('high-contrast.highlightedStackFrame.bgColor');
99 | this.highContrast_list_tuple_setTbl_bgColor = pythonConfig.get('high-contrast.list-tuple-setTbl.bgColor');
100 | this.highContrast_dict_class_instKey_bgColor = pythonConfig.get('high-contrast.dict-class-instKey.bgColor');
101 | this.highContrast_dict_class_instVal_bgColor = pythonConfig.get('high-contrast.dict-class-instVal.bgColor');
102 | this.styles = pythonConfig.get('styles', []);
103 | }
104 |
105 | public equals(otherConfig: StyleConfiguration) {
106 | for (let key in this) {
107 | if (this.hasOwnProperty(key) && key !== 'styles' && this[key] !== otherConfig[key]) {
108 | return false;
109 | }
110 | }
111 |
112 | if (this.styles.length !== otherConfig.styles.length) {
113 | return false;
114 | }
115 |
116 | for (let i = 0; i < this.styles.length; ++i) {
117 | if (this.styles[i] !== otherConfig.styles[i]) {
118 | return false;
119 | }
120 | }
121 |
122 | return true;
123 | }
124 | }
125 |
126 | class ContentConfiguration {
127 | [key: string]: any;
128 | public readonly disableHeapNesting: boolean;
129 | public readonly textualMemoryLabels: boolean;
130 | public readonly compactFuncLabels: boolean;
131 | public readonly showAllFrameLabels: boolean;
132 | public readonly hideCode: boolean;
133 | public readonly codAndNavWidth: number;
134 |
135 | public constructor(pythonConfig: vscode.WorkspaceConfiguration) {
136 | this.disableHeapNesting = !!pythonConfig.get('disableHeapNesting', false);
137 | this.textualMemoryLabels = !!pythonConfig.get('textualMemoryLabels', false);
138 | this.compactFuncLabels = !!pythonConfig.get('compactFuncLabels', false);
139 | this.showAllFrameLabels = !!pythonConfig.get('showAllFrameLabels', false);
140 | this.hideCode = !!pythonConfig.get('hideCode', false);
141 | this.codAndNavWidth = Math.max(510, +pythonConfig.get('codAndNavWidth', 510));
142 | }
143 |
144 | public equals(otherConfig: ContentConfiguration) {
145 | for (let key in this) {
146 | if (this.hasOwnProperty(key) && this[key] !== otherConfig[key]) {
147 | return false;
148 | }
149 | }
150 | return true;
151 | }
152 | }
153 |
154 | class TraceConfiguration {
155 | [key: string]: any;
156 | public readonly cumulativeMode: boolean;
157 | public readonly allowAllModules: boolean;
158 |
159 | public readonly maxExecutedLines: number;
160 |
161 | public constructor(pythonConfig: vscode.WorkspaceConfiguration) {
162 | this.cumulativeMode = !!pythonConfig.get('cumulativeMode', false);
163 | this.allowAllModules = !!pythonConfig.get('allowAllModules', true);
164 | this.maxExecutedLines = Math.max(1000, +pythonConfig.get('maxExecutedLines', 1000));
165 | }
166 |
167 | public equals(otherConfig: TraceConfiguration) {
168 | for (let key in this) {
169 | if (this.hasOwnProperty(key) && this[key] !== otherConfig[key]) {
170 | return false;
171 | }
172 | }
173 | return true;
174 | }
175 | }
176 |
177 | export class PythonPreviewConfiguration {
178 | public static getForResource(resouce: vscode.Uri) {
179 | return new PythonPreviewConfiguration(resouce);
180 | }
181 |
182 | public readonly styleConfig: StyleConfiguration;
183 | public readonly contentConfig: ContentConfiguration;
184 | public readonly traceConfig: TraceConfiguration;
185 |
186 | private constructor(resource: vscode.Uri) {
187 | const pythonConfig = vscode.workspace.getConfiguration('pythonPreview', resource);
188 | this.styleConfig = new StyleConfiguration(pythonConfig);
189 | this.contentConfig = new ContentConfiguration(pythonConfig);
190 | this.traceConfig = new TraceConfiguration(pythonConfig);
191 | }
192 |
193 | public equals(otherConfig: PythonPreviewConfiguration) {
194 | if (!this.styleConfig.equals(otherConfig.styleConfig)) return false;
195 | if (!this.contentConfig.equals(otherConfig.contentConfig)) return false;
196 | if (!this.traceConfig.equals(otherConfig.traceConfig)) return false;
197 | return true;
198 | }
199 | }
200 |
201 | export class PythonPreviewConfigurationManager {
202 | private readonly _previewConfigurationsForWorkspaces = new Map();
203 |
204 | public loadAndCacheConfiguration(resource: vscode.Uri): PythonPreviewConfiguration {
205 | const config = PythonPreviewConfiguration.getForResource(resource);
206 | this._previewConfigurationsForWorkspaces.set(this.getKey(resource), config);
207 | return config;
208 | }
209 |
210 | public getConfigCacheForResource(resource: vscode.Uri): PythonPreviewConfiguration {
211 | let config = this._previewConfigurationsForWorkspaces.get(this.getKey(resource));
212 | if (!config) {
213 | config = PythonPreviewConfiguration.getForResource(resource);
214 | this._previewConfigurationsForWorkspaces.set(this.getKey(resource), config);
215 | }
216 | return config;
217 | }
218 |
219 | public hasConfigurationChanged(resource: vscode.Uri): boolean {
220 | const key = this.getKey(resource);
221 | const currentConfig = this._previewConfigurationsForWorkspaces.get(key);
222 | const newConfig = PythonPreviewConfiguration.getForResource(resource);
223 | return !(currentConfig && currentConfig.equals(newConfig));
224 | }
225 |
226 | private getKey(resource: vscode.Uri): string {
227 | const folder = vscode.workspace.getWorkspaceFolder(resource);
228 | return folder ? folder.uri.toString() : '';
229 | }
230 | }
--------------------------------------------------------------------------------
/src/features/previewContentProvider.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from "vscode";
2 | import * as path from 'path';
3 | import {Logger} from "../common/logger";
4 | import {PythonPreviewConfiguration, PythonPreviewConfigurationManager} from "./previewConfig";
5 |
6 | export class PythonContentProvider {
7 | constructor(private readonly _context: vscode.ExtensionContext,
8 | private readonly _logger: Logger) {
9 | }
10 |
11 | public provideTextDocumentContent(pythonDocument: vscode.TextDocument,
12 | previewConfigurationManager: PythonPreviewConfigurationManager,
13 | state?: any): string {
14 | const sourceUri = pythonDocument.uri;
15 | const config = previewConfigurationManager.loadAndCacheConfiguration(sourceUri);
16 |
17 | // Content Security Policy
18 | const nonce = new Date().getTime() + '' + new Date().getMilliseconds();
19 |
20 | return `
21 |
22 |
23 |
24 |
25 |
27 | ${this.getStyles(sourceUri, nonce, config)}
28 |
29 |
30 |
31 |
32 |
33 |
34 | `;
35 | }
36 |
37 | private fixHref(resource: vscode.Uri, href: string): string {
38 | if (!href) {
39 | return href;
40 | }
41 |
42 | const hrefUri = vscode.Uri.parse(href);
43 | if (['http', 'https'].indexOf(hrefUri.scheme) >= 0) {
44 | return hrefUri.toString();
45 | }
46 |
47 | if (path.isAbsolute(href) || hrefUri.scheme === 'file') {
48 | return vscode.Uri.file(href).with({scheme: 'vscode-resource'}).toString();
49 | }
50 |
51 | let root = vscode.workspace.getWorkspaceFolder(resource);
52 | if (root) {
53 | return vscode.Uri.file(path.join(root.uri.fsPath, href)).with({scheme: 'vscode-resource'}).toString();
54 | }
55 |
56 | return vscode.Uri.file(path.join(path.dirname(resource.fsPath), href)).with({scheme: 'vscode-resource'}).toString();
57 | }
58 |
59 | private getSettingsOverrideStyles(nonce: string, config: PythonPreviewConfiguration): string {
60 | return ``;
201 | }
202 |
203 | private getCustomStyles(resource: vscode.Uri, config: PythonPreviewConfiguration): string {
204 | if (Array.isArray(config.styleConfig.styles)) {
205 | return config.styleConfig.styles.map(style => {
206 | return ``
207 | }).join('\n');
208 | }
209 | return '';
210 | }
211 |
212 | private getStyles(resource: vscode.Uri, nonce: string, config: PythonPreviewConfiguration): string {
213 | const baseStyles = ['jquery-ui.min.css', 'pytutor.common.css', 'pytutor.theme.css']
214 | .map(item => ``)
215 | .join('\n');
216 |
217 | return `${baseStyles}
218 | ${this.getSettingsOverrideStyles(nonce, config)}
219 | ${this.getCustomStyles(resource, config)}`;
220 | }
221 |
222 | private extensionResourcePath(assetFile: string): string {
223 | return vscode.Uri.file(this._context.asAbsolutePath(path.join('assets', assetFile)))
224 | .with({ scheme: 'vscode-resource' })
225 | .toString();
226 | }
227 | }
--------------------------------------------------------------------------------
/src/features/previewManager.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from "vscode";
2 | import * as path from 'path';
3 | import {PythonPreviewConfigurationManager} from "./previewConfig";
4 | import {PythonPreview} from "./preview";
5 | import {PythonContentProvider} from "./previewContentProvider";
6 | import {Logger} from "../common/logger";
7 | import {disposeAll} from "../common/dispose";
8 | import { IDebugServer, LaunchRequestArguments } from "../debugger/common/contracts";
9 | import { PythonProcess } from "../debugger/pythonProcess";
10 | import { BaseDebugClient } from "../debugger/debugClients/baseDebugClient";
11 | import { BaseDebugServer } from "../debugger/debugServers/baseDebugServer";
12 | import { getPythonExecutable } from "../debugger/common/utils";
13 | import { DebuggerLauncherScriptProvider } from "../debugger/debugClients/launcherProvider";
14 | import { LocalDebugClient } from "../debugger/debugClients/localDebugClient";
15 | import { PythonOutput, PythonOutputStatus } from "./pythonOutput";
16 | import { isNotInstalledError } from "../common/helpers";
17 |
18 | export class PythonPreviewManager implements vscode.WebviewPanelSerializer {
19 | private static readonly _pythonPreviewActiveContextKey = 'pythonPreviewFocus';
20 |
21 | private readonly _previewConfigurationManager = new PythonPreviewConfigurationManager();
22 | private _previews: PythonPreview[] = [];
23 | private _activePreview: PythonPreview | undefined = undefined;
24 | private readonly _disposables: vscode.Disposable[] = [];
25 |
26 | private _debuggerLoaded: Promise | undefined;
27 | private _debuggerLoadedPromiseResolve!: () => void;
28 | private _pythonProcess?: PythonProcess;
29 | private _debugClient?: BaseDebugClient<{}>;
30 | private _debugServer!: BaseDebugServer;
31 | private _launchArgs!: LaunchRequestArguments;
32 | private _cachedOutputs: Map;
33 | private _lang?: string;
34 |
35 | public constructor(private readonly _context: vscode.ExtensionContext,
36 | private readonly _contentProvider: PythonContentProvider,
37 | private readonly _logger: Logger){
38 | this._disposables.push(vscode.window.registerWebviewPanelSerializer(PythonPreview.viewtype, this));
39 | this._cachedOutputs = new Map();
40 | }
41 |
42 | public dispose(): void {
43 | disposeAll(this._disposables);
44 | disposeAll(this._previews);
45 | this._cachedOutputs.clear();
46 | this.stopDebugServer();
47 | }
48 |
49 | public refresh() {
50 | for (const preview of this._previews) {
51 | preview.initialContent();
52 | }
53 | }
54 |
55 | public updateConfiguration() {
56 | for (const preview of this._previews) {
57 | preview.updateConfiguration();
58 | }
59 | }
60 |
61 | public preview(resource: vscode.Uri, previewSettings: PreviewSettings): void {
62 | // 第一次预览,首先创建调试器。
63 | if (this._debuggerLoaded === undefined) {
64 | this._launchArgs = {
65 | pythonPath: 'python'
66 | };
67 | this._debuggerLoaded = new Promise(resolve => {
68 | this._debuggerLoadedPromiseResolve = resolve;
69 | });
70 | this.createDebugger(this._launchArgs);
71 | }
72 | // 这段代码永远找不到已存在的preview,原因是preview的列输入参数是vscode.ViewColumn.Beside或者vscode.ViewColumn.Beside!!!
73 | let preview = this.getExistingPreview(resource, previewSettings);
74 | if (preview) {
75 | preview.reveal(previewSettings.previewColumn);
76 | } else {
77 | preview = this.createNewPreview(resource, previewSettings);
78 | preview.initialContent();
79 | }
80 | }
81 |
82 | public get activePreviewResource(): vscode.Uri | undefined {
83 | return this._activePreview && this._activePreview.resource;
84 | }
85 |
86 | public get lang() {
87 | return this._lang;
88 | }
89 |
90 | public toggleLock() {
91 | const preview = this._activePreview;
92 | if (preview) {
93 | preview.toggleLock();
94 | // 关闭冗余的预览
95 | for (const otherPreview of this._previews) {
96 | if (otherPreview !== preview && preview.matches(otherPreview)) {
97 | otherPreview.dispose();
98 | }
99 | }
100 | }
101 | }
102 |
103 | public async deserializeWebviewPanel(webviewPanel: vscode.WebviewPanel, state: any): Promise {
104 |
105 | const preview = await PythonPreview.receive(
106 | webviewPanel,
107 | state,
108 | this,
109 | this._context,
110 | this._cachedOutputs,
111 | this._contentProvider,
112 | this._previewConfigurationManager,
113 | this._logger);
114 |
115 | this.registerPreview(preview);
116 | }
117 |
118 |
119 |
120 | private getExistingPreview(resource: vscode.Uri, previewSettings: PreviewSettings): PythonPreview | undefined {
121 | return this._previews.find(preview =>
122 | preview.matchesResource(resource, previewSettings.previewColumn, previewSettings.locked));
123 | }
124 |
125 | private createNewPreview(resource: vscode.Uri, previewSettings: PreviewSettings): PythonPreview {
126 | const preview = PythonPreview.create(resource,
127 | previewSettings.previewColumn,
128 | previewSettings.locked,
129 | this,
130 | this._context,
131 | this._cachedOutputs,
132 | this._contentProvider,
133 | this._previewConfigurationManager,
134 | this._logger);
135 |
136 | this.setPreviewActiveContext(true);
137 | this._activePreview = preview;
138 | return this.registerPreview(preview);
139 | }
140 |
141 | private registerPreview(preview: PythonPreview): PythonPreview {
142 | this._previews.push(preview);
143 |
144 | preview.onDidDispose(() => {
145 | const existing = this._previews.indexOf(preview);
146 | if (existing === -1) {
147 | return;
148 | }
149 | this._previews.splice(existing, 1);
150 | if (this._activePreview === preview) {
151 | this.setPreviewActiveContext(false);
152 | this._activePreview = undefined;
153 | }
154 | if (this._previews.length === 0) {
155 | this.stopDebugServer();
156 | this._cachedOutputs.clear();
157 | } else {
158 | const isSameResource = this._previews.some(item => {
159 | if (item.resource.fsPath == preview.resource.fsPath) return true;
160 | });
161 | if (!isSameResource && this._cachedOutputs.has(preview.resource.fsPath)) {
162 | this._cachedOutputs.delete(preview.resource.fsPath);
163 | }
164 | }
165 |
166 | });
167 |
168 | preview.onDidChangeViewState(({ webviewPanel }) => {
169 | disposeAll(this._previews.filter(otherPreview => preview !== otherPreview && preview!.matches(otherPreview)));
170 | this.setPreviewActiveContext(webviewPanel.active);
171 | this._activePreview = webviewPanel.active ? preview : undefined;
172 | });
173 |
174 | return preview;
175 | }
176 |
177 | private setPreviewActiveContext(value: boolean) {
178 | vscode.commands.executeCommand('setContext', PythonPreviewManager._pythonPreviewActiveContextKey, value);
179 | }
180 |
181 | public createDebugger(args: LaunchRequestArguments): void {
182 | try {
183 | args.pythonPath = getPythonExecutable(args.pythonPath);
184 | } catch (ex) { }
185 |
186 | this._launchArgs = args;
187 | let launchScriptProvider = new DebuggerLauncherScriptProvider();
188 | this._debugClient = new LocalDebugClient(args, launchScriptProvider, this, this._logger);
189 |
190 | const that = this;
191 | this.startDebugServer().then(debugServer => {
192 | this._logger.info(`Started Debug Server. It is listening port - ${debugServer.port}`);
193 | return that._debugClient!.launchApplicationToDebug(debugServer);
194 | }).catch(error => {
195 | let errorMsg = typeof error === 'string' ? error : ((error.message && error.message.length > 0) ? error.message : error);
196 | if (isNotInstalledError(error)) {
197 | errorMsg = `Failed to launch the Python Process, please valiate the path '${this._launchArgs.pythonPath}'`;
198 | }
199 | vscode.window.showErrorMessage(errorMsg);
200 | this._logger.error('Starting Debugger with error.', errorMsg);
201 | this.dispose();
202 | });
203 | }
204 |
205 | private initializeEventHandlers() {
206 | const pythonProcess = this._pythonProcess!;
207 | pythonProcess.on('processLoaded', pythonVersion => this.onPythonProcessLoaded(pythonVersion));
208 | pythonProcess.on('output', (fileName, output) => this.onDebuggerOutput(fileName, output));
209 | pythonProcess.on('detach', () => this.onDetachDebugger());
210 |
211 | this._debugServer.on('detach', () => this.onDetachDebugger());
212 | }
213 |
214 | public postMessageToDebugger(fileName: string, code: string) {
215 | if (this._debuggerLoaded === undefined) {
216 | this._launchArgs = {
217 | pythonPath: 'python'
218 | };
219 | this._debuggerLoaded = new Promise(resolve => {
220 | this._debuggerLoadedPromiseResolve = resolve;
221 | });
222 | this.createDebugger(this._launchArgs);
223 | }
224 | this._debuggerLoaded.then(() => {
225 | let output = this._cachedOutputs.get(fileName);
226 | // 第一次传送数据,则直接传送
227 | if (!output) {
228 | this._cachedOutputs.set(fileName, new PythonOutput());
229 | this.sendMessage(fileName, code);
230 | output.status = PythonOutputStatus.Initialized;
231 | } else {
232 | // 如果是之后的传送,则设置定时器
233 | clearTimeout(output.throttleTimer);
234 | output.throttleTimer = setTimeout(() => {
235 | this.sendMessage(fileName, code);
236 | output.status = PythonOutputStatus.Processing;
237 | output.throttleTimer = undefined;
238 | }, 300);
239 | }
240 | });
241 | }
242 |
243 | private sendMessage(fileName: string, code: string) {
244 | const config = this._previewConfigurationManager.getConfigCacheForResource(vscode.Uri.file(fileName));
245 | const folder = PythonPreviewManager.getWorkspacePathOrPathRealtiveToFile(fileName);
246 | const cumulativeMode = config.traceConfig.cumulativeMode;
247 | const allowAllModules = config.traceConfig.allowAllModules;
248 | const maxExecutedLines = config.traceConfig.maxExecutedLines;
249 | this._logger.info('Sending executed code to debugger');
250 | this._pythonProcess!.sendExecutableText(folder, fileName, code, cumulativeMode, allowAllModules, maxExecutedLines);
251 | }
252 |
253 | private static getWorkspacePathOrPathRealtiveToFile(fileName: string) {
254 | let root = vscode.workspace.getWorkspaceFolder(vscode.Uri.file(fileName));
255 | if (root) {
256 | return root.uri.fsPath;
257 | }
258 | return path.dirname(fileName);
259 | }
260 |
261 | private onPythonProcessLoaded(pythonVersion: string) {
262 | this._logger.info('Python Process loaded');
263 | this._lang = `Python ${pythonVersion}`;
264 | this._debuggerLoadedPromiseResolve();
265 | }
266 |
267 | private onDebuggerOutput(fileName: string, output: string) {
268 | const data = JSON.parse(output);
269 | let cacheOutput = this._cachedOutputs.get(fileName)!;
270 | cacheOutput.status = PythonOutputStatus.Prcoessed;
271 | cacheOutput.trace = data;
272 | this._previews.forEach(item => {
273 | if (item.isPreviewOf(vscode.Uri.file(fileName))) {
274 | if (item.visibale) {
275 | item.updateContent();
276 | }
277 | }
278 | });
279 | }
280 |
281 | public onDetachDebugger() {
282 | this.stopDebugServer();
283 | }
284 |
285 | private startDebugServer(): Promise {
286 | this._pythonProcess = new PythonProcess(0, '');
287 | this._debugServer = this._debugClient!.createDebugServer(this._pythonProcess);
288 | this.initializeEventHandlers();
289 | this._logger.info('Starting Debug Server');
290 | return this._debugServer.start();
291 | }
292 |
293 | private stopDebugServer() {
294 | if (this._debugClient) {
295 | this._debugClient!.stop();
296 | this._debugClient = undefined;
297 | }
298 | if (this._pythonProcess) {
299 | this._pythonProcess!.kill();
300 | this._pythonProcess = undefined;
301 | }
302 | this._debuggerLoaded = undefined;
303 | if (this._lang) {
304 | this._lang = undefined;
305 | this._logger.info('Debugger exited');
306 | }
307 | }
308 |
309 | }
310 |
311 | export interface PreviewSettings {
312 | readonly resourceColumn: vscode.ViewColumn;
313 | readonly previewColumn: vscode.ViewColumn;
314 | readonly locked: boolean;
315 | }
--------------------------------------------------------------------------------
/src/features/pythonOutput.ts:
--------------------------------------------------------------------------------
1 | export enum PythonOutputStatus {
2 | Initialized = 1,
3 | Processing = 2,
4 | Prcoessed = 3
5 | }
6 |
7 | export class PythonOutput {
8 | private _status: PythonOutputStatus;
9 |
10 | public constructor(private _trace?: any, private _throttleTimer?: NodeJS.Timer) {
11 | this._status = PythonOutputStatus.Initialized;
12 | }
13 |
14 | public get trace() {
15 | return this._trace;
16 | }
17 |
18 | public set trace(value) {
19 | this._trace = value;
20 | }
21 |
22 | public get status() {
23 | return this._status;
24 | }
25 |
26 | public set status(value) {
27 | this._status = value;
28 | }
29 |
30 | public get throttleTimer() {
31 | return this._throttleTimer;
32 | }
33 |
34 | public set throttleTimer(value) {
35 | this._throttleTimer = value;
36 | }
37 | }
--------------------------------------------------------------------------------
/src/test/common/net/socketStream.test.ts:
--------------------------------------------------------------------------------
1 | import * as net from 'net';
2 | import * as assert from 'assert';
3 |
4 | import { SocketStream } from '../../../common/net/socket/socketStream';
5 | const uint64be = require('uint64be');
6 |
7 | class MockSocket {
8 | private _rawDataWritten: any;
9 | constructor(private _data: string = '') { }
10 |
11 | public get dataWritten(): string {
12 | return this._data;
13 | }
14 |
15 | public get rawDataWritten(): any {
16 | return this._rawDataWritten;
17 | }
18 |
19 | write(data: any) {
20 | this._data = data + '';
21 | this._rawDataWritten = data;
22 | }
23 | }
24 |
25 | suite('SocketStream', () => {
26 | test('Read Byte', done => {
27 | let buffer = Buffer.from('P');
28 | const byteValue = buffer[0];
29 | const socket = new MockSocket();
30 | const stream = new SocketStream((socket as any) as net.Socket, buffer);
31 |
32 | assert.equal(stream.readByte(), byteValue);
33 | done();
34 | });
35 |
36 | test('Read Int32', done => {
37 | const max = 2147483648;
38 | const socket = new MockSocket();
39 | let buffer = uint64be.encode(max);
40 | const stream = new SocketStream((socket as any) as net.Socket, buffer);
41 |
42 | assert.equal(stream.readInt32(), max);
43 | done();
44 | });
45 |
46 | test('Read Int64', done => {
47 | const max = 9223372036854775807;
48 | const socket = new MockSocket();
49 | let buffer = uint64be.encode(max);
50 | const stream = new SocketStream((socket as any) as net.Socket, buffer);
51 |
52 | assert.equal(stream.readInt64(), max);
53 | done();
54 | });
55 |
56 | test('Read Ascii String', done => {
57 | const message = 'Hello World';
58 | const socket = new MockSocket();
59 | let buffer = Buffer.concat([Buffer.from('A'), uint64be.encode(message.length), Buffer.from(message)]);
60 | const stream = new SocketStream((socket as any) as net.Socket, buffer);
61 |
62 | assert.equal(stream.readString(), message);
63 | done();
64 | })
65 |
66 | test('Read Unicode String', done => {
67 | const message = 'Hello World - Функция проверки ИНН и КПП - 说明';
68 | const socket = new MockSocket();
69 | const stringBuffer = Buffer.from(message);
70 | let buffer = Buffer.concat([Buffer.from('U'), uint64be.encode(stringBuffer.byteLength), stringBuffer]);
71 | const stream = new SocketStream((socket as any) as net.Socket, buffer);
72 |
73 | assert.equal(stream.readString(), message);
74 | done();
75 | });
76 |
77 |
78 | })
--------------------------------------------------------------------------------
/src/test/extension.test.ts:
--------------------------------------------------------------------------------
1 | //
2 | // Note: This example test is leveraging the Mocha test framework.
3 | // Please refer to their documentation on https://mochajs.org/ for help.
4 | //
5 |
6 | // The module 'assert' provides assertion methods from node
7 | import * as assert from 'assert';
8 |
9 | // You can import and use all API from the 'vscode' module
10 | // as well as import your extension to test it
11 | import * as vscode from 'vscode';
12 | import * as myExtension from '../extension';
13 |
14 | // Defines a Mocha test suite to group tests of similar kind together
15 | suite("Extension Tests", () => {
16 |
17 | // Defines a Mocha unit test
18 | test("Something 1", () => {
19 | assert.equal(-1, [1, 2, 3].indexOf(5));
20 | assert.equal(-1, [1, 2, 3].indexOf(0));
21 | });
22 | });
--------------------------------------------------------------------------------
/src/test/index.ts:
--------------------------------------------------------------------------------
1 | //
2 | // PLEASE DO NOT MODIFY / DELETE UNLESS YOU KNOW WHAT YOU ARE DOING
3 | //
4 | // This file is providing the test runner to use when running extension tests.
5 | // By default the test runner in use is Mocha based.
6 | //
7 | // You can provide your own test runner if you want to override it by exporting
8 | // a function run(testRoot: string, clb: (error:Error) => void) that the extension
9 | // host can call to run the tests. The test runner is expected to use console.log
10 | // to report the results back to the caller. When the tests are finished, return
11 | // a possible error to the callback or null if none.
12 |
13 | import * as testRunner from 'vscode/lib/testrunner';
14 |
15 | // You can directly control Mocha options by uncommenting the following lines
16 | // See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options for more info
17 | testRunner.configure({
18 | ui: 'tdd', // the TDD UI is being used in extension.test.ts (suite, test, etc.)
19 | useColors: true // colored output from test results
20 | });
21 |
22 | module.exports = testRunner;
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "es6",
5 | "outDir": "out",
6 | "lib": [
7 | "es6"
8 | ],
9 | "sourceMap": true,
10 | "rootDir": "src",
11 | "experimentalDecorators": true
12 | /* Strict Type-Checking Option */
13 | // "strict": true, /* enable all strict type-checking options */
14 | /* Additional Checks */
15 | // "noUnusedLocals": true /* Report errors on unused locals. */
16 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
17 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
18 | // "noUnusedParameters": true, /* Report errors on unused parameters. */
19 | },
20 | "exclude": [
21 | "node_modules",
22 | ".vscode-test",
23 | "out",
24 | "preview-src"
25 | ]
26 | }
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "no-string-throw": true,
4 | "no-unused-expression": true,
5 | "no-duplicate-variable": true,
6 | "curly": true,
7 | "class-name": true,
8 | "semicolon": [
9 | true,
10 | "always"
11 | ],
12 | "triple-equals": true
13 | },
14 | "defaultSeverity": "warning"
15 | }
--------------------------------------------------------------------------------