├── .eslintrc.json
├── .github
└── workflows
│ └── ci.yml
├── .gitignore
├── .jsbeautifyrc
├── Gruntfile.js
├── LICENSE
├── README.md
├── app
├── __init__.py
├── static
│ ├── 16.png
│ ├── 32.png
│ ├── about.html
│ ├── cm
│ │ ├── Readme.md
│ │ ├── active-line.js
│ │ ├── clike.js
│ │ ├── codemirror.css
│ │ ├── codemirror.js
│ │ ├── matchbrackets.js
│ │ ├── show-hint.css
│ │ └── show-hint.js
│ ├── cookie-policy.html
│ ├── css
│ │ └── s.css
│ ├── examples.html
│ ├── favicon.ico
│ ├── img
│ │ ├── ce.svg
│ │ ├── clb.svg
│ │ ├── logo.svg
│ │ ├── nav-dark.svg
│ │ ├── nav.svg
│ │ ├── qb.svg
│ │ └── twcard.png
│ ├── js
│ │ ├── cookie.js
│ │ ├── main.js
│ │ └── settings.js
│ ├── ms
│ │ ├── Readme.md
│ │ ├── jquery-3.3.1.js
│ │ └── multiple-select.js
│ ├── privacy-policy.html
│ ├── robots.txt
│ ├── settings.html
│ └── sitemap.xml
└── templates
│ ├── 404.html
│ ├── index.html
│ └── version.html
├── deploy_rsa.enc
├── insights.wsgi
├── local.py
├── package.json
├── pics
├── window-maximize.svg
└── window-minimize.svg
├── requirements.txt
├── requirements_gh.txt
├── test.py
└── test
└── cookie.test.js
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "node": true,
5 | "commonjs": true,
6 | "es6": true,
7 | "jquery": true
8 | },
9 | "extends": "eslint:recommended",
10 | "parserOptions": {
11 | "ecmaVersion": 2018
12 | },
13 | "rules": {
14 | "indent": [
15 | "error",
16 | 2
17 | ],
18 | "linebreak-style": [
19 | "error",
20 | "unix"
21 | ],
22 | "quotes": [
23 | "error",
24 | "single"
25 | ],
26 | "semi": [
27 | "error",
28 | "always"
29 | ]
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: Scheduled
2 | on:
3 | push:
4 | branches-ignore:
5 | - 'continuous'
6 |
7 | pull_request:
8 | branches-ignore:
9 | - 'continuous'
10 |
11 | jobs:
12 | build:
13 | name: Build C++ Insights Web
14 | runs-on: ubuntu-latest
15 | steps:
16 | - uses: actions/checkout@v4
17 | with:
18 | fetch-depth: 0
19 | - name: Setup Node.js for use with actions
20 | uses: actions/setup-node@v4
21 | with:
22 | node-version: '18'
23 | cache: 'npm'
24 | cache-dependency-path: '**/package.json'
25 |
26 | - name: Setup Python environment
27 | uses: actions/setup-python@v5
28 | with:
29 | python-version: '3.7' # Server has 3.5
30 |
31 | - name: Install SSH Key
32 | uses: shimataro/ssh-key-action@v1.3.0
33 | with:
34 | private-key: ${{ secrets.SSH_PRIVATE_KEY }}
35 | public-key: ${{ secrets.SSH_PUBLIC_KEY }}
36 | known-hosts: ${{ secrets.SSH_KNOWN_HOSTS }}
37 |
38 | - name: Install python
39 | run: pip install -r requirements_gh.txt
40 |
41 | - name: Install node modules
42 | run: |
43 | npm set progress=false
44 | npm install -g grunt-cli
45 | npm install
46 |
47 | - name: Generate
48 | run: grunt
49 |
50 | - name: Run coverage
51 | run: coverage run test.py
52 |
53 | - name: Upload code coverage info
54 | run: bash <(curl -s https://codecov.io/bash) -cF python
55 |
56 | #------------------------------------------------------------------------------
57 | # DEPLOY
58 | #------------------------------------------------------------------------------
59 | deploy:
60 | needs: [build]
61 | if: github.ref == 'refs/heads/main'
62 | name: Final Deploy
63 | runs-on: ubuntu-latest
64 |
65 | steps:
66 | - uses: actions/checkout@v4
67 | with:
68 | fetch-depth: 0
69 | - name: Setup Node.js for use with actions
70 | uses: actions/setup-node@v4
71 | with:
72 | node-version: '18'
73 | cache: 'npm'
74 | cache-dependency-path: '**/package.json'
75 |
76 | - name: Setup Python environment
77 | uses: actions/setup-python@v5
78 | with:
79 | python-version: '3.7' # Server has 3.5
80 |
81 | - name: Install SSH Key
82 | uses: shimataro/ssh-key-action@v1.3.0
83 | with:
84 | private-key: ${{ secrets.SSH_PRIVATE_KEY }}
85 | public-key: ${{ secrets.SSH_PUBLIC_KEY }}
86 | known-hosts: ${{ secrets.SSH_KNOWN_HOSTS }}
87 |
88 | - name: Install python
89 | run: pip install -r requirements_gh.txt
90 |
91 | - name: Install node modules
92 | run: |
93 | npm set progress=false
94 | npm install -g grunt-cli
95 | npm install
96 |
97 | - name: Generate
98 | run: grunt
99 |
100 | - name: Update latest tag
101 | uses: richardsimko/update-tag@v1
102 | with:
103 | tag_name: latest
104 | env:
105 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
106 |
107 | - name: Publish
108 | run: rsync -avcz --delete --exclude=.DS_Store --exclude=__pycache__ --exclude='google*.html' --exclude='urls.db' ${GITHUB_WORKSPACE}/dist/app/ ${{ secrets.SSH_HOST_NEW }}
109 |
110 | - name: Notify listeners
111 | run: |
112 | curl -X POST -H "Accept: application/vnd.github.v3+json" -H "Authorization: token ${{ secrets.GH_TRIGGER }}" https://api.github.com/repos/andreasfertig/cppinsights-webfrontend-container/dispatches -d '{"event_type":"rebuild_trigger"}' &> /dev/null
113 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.idea
2 | /dist
3 | /node_modules
4 |
--------------------------------------------------------------------------------
/.jsbeautifyrc:
--------------------------------------------------------------------------------
1 | {
2 | "indent_size": 2,
3 | "indent_char": " ",
4 | "indent_with_tabs": false,
5 | "preserve_newlines": true,
6 | "max_preserve_newlines": 2,
7 | "space_after_anon_function": false,
8 | "brace_style": "collapse",
9 | "eol": "\n",
10 | "keep_function_indentation": false,
11 | "space_before_conditional": true,
12 | "break_chained_methods": false,
13 | "eval_code": false,
14 | "unescape_strings": false,
15 | "wrap_attributes": "auto",
16 | "wrap_attributes_indent_size": 4,
17 | "end_with_newline": true,
18 | "wrap_line_length": 120
19 | }
20 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 |
3 | grunt.initConfig({
4 | svgmin: {
5 | options: {
6 | plugins: [{
7 | name: 'preset-default',
8 | params: {
9 | overrides: {
10 | removeViewBox: false,
11 | removeEmptyAttrs: false,
12 | removeUselessStrokeAndFill: false,
13 | },
14 | },
15 | }]
16 | },
17 | dist: {
18 | files: [{
19 | expand: true,
20 | cwd: 'app/static/img/',
21 | src: ['*.svg'],
22 | dest: 'dist/app/static/img',
23 | ext: '.svg'
24 | }]
25 | }
26 | },
27 |
28 | cssmin: {
29 | target: {
30 | files: [{
31 | expand: true,
32 | cwd: 'app/static/css',
33 | src: ['*.css', '!*.min.css'],
34 | dest: 'dist/app/static/css',
35 | ext: '.min.css'
36 | },
37 | {
38 | 'dist/app/static/cm/cm.min.css': ['app/static/cm/codemirror.css', 'app/static/cm/show-hint.css']
39 | },
40 | ]
41 | }
42 | },
43 |
44 | uglify: {
45 | options: {
46 | mangle: false
47 | },
48 | cmjs: {
49 | files: {
50 | 'dist/app/static/cm/cm.min.js': ['app/static/cm/codemirror.js', 'app/static/cm/active-line.js',
51 | 'app/static/cm/clike.js', 'app/static/cm/matchbrackets.js', 'app/static/cm/show-hint.js'
52 | ],
53 | 'dist/app/static/js/main.min.js': ['app/static/js/main.js'],
54 | 'dist/app/static/js/cookie.min.js': ['app/static/js/cookie.js'],
55 | 'dist/app/static/js/settings.min.js': ['app/static/js/settings.js'],
56 | 'dist/app/static/ms/jquery-3.3.1.min.js': ['app/static/ms/jquery-3.3.1.js'],
57 | 'dist/app/static/ms/multiple-select.min.js': ['app/static/ms/multiple-select.js']
58 | }
59 | }
60 | },
61 |
62 | 'string-replace': {
63 | inline: {
64 | files: [{
65 | 'dist/tmp/': 'app/templates/*.html'
66 | },
67 | {
68 | 'dist/tmp/': 'app/static/*.html'
69 | },
70 | ],
71 | options: {
72 | replacements: [{
73 | pattern: /([\s\S]*?)/g,
74 | replacement: ' '
75 | },
76 | {
77 | pattern: /s\.css/ig,
78 | replacement: 's.min.css'
79 | },
80 | {
81 | pattern: /gh\.css/ig,
82 | replacement: 'gh.min.css'
83 | },
84 | {
85 | pattern: /main\.js/ig,
86 | replacement: 'main.min.js'
87 | },
88 | {
89 | pattern: /cookie\.js/ig,
90 | replacement: 'cookie.min.js'
91 | },
92 | {
93 | pattern: /settings\.js/ig,
94 | replacement: 'settings.min.js'
95 | },
96 | {
97 | pattern: /jquery-3.3.1\.js/ig,
98 | replacement: 'jquery-3.3.1.min.js'
99 | },
100 | {
101 | pattern: /multiple-select\.js/ig,
102 | replacement: 'multiple-select.min.js'
103 | },
104 | ]
105 | }
106 | }
107 | },
108 |
109 | htmlmin: {
110 | dist: {
111 | options: {
112 | removeComments: true,
113 | collapseWhitespace: true,
114 | conservativeCollapse: true
115 | },
116 | files: [{
117 | expand: true,
118 | cwd: 'dist/tmp/app/templates/',
119 | src: ['*.html', '*.html'],
120 | dest: 'dist/app/templates/'
121 | },
122 |
123 | {
124 | expand: true,
125 | cwd: 'dist/tmp/app/static/',
126 | src: ['*.html', '*.html'],
127 | dest: 'dist/app/static/'
128 | },
129 |
130 | {
131 | expand: true,
132 | cwd: 'app/static/',
133 | src: ['*.xml', '*.xml'],
134 | dest: 'dist/app/static/'
135 | },
136 | ]
137 | },
138 | },
139 |
140 | copy: {
141 | main: {
142 | options: {
143 | mode: true,
144 | },
145 | files: [{
146 | expand: true,
147 | filter: 'isFile',
148 | src: [
149 | 'app/*.py',
150 | 'app/static/favicon.ico',
151 | 'app/static/robots.txt',
152 | ],
153 | dest: 'dist/',
154 | }, ],
155 | },
156 | },
157 |
158 | imagemin: {
159 | compile: {
160 | options: {
161 | ext: '.png',
162 | quality: '80-90',
163 | force: true
164 | },
165 | files: [{
166 | expand: true,
167 | src: ['**/*.png'],
168 | cwd: 'app/static//',
169 | dest: 'dist/app/static/'
170 | }]
171 | }
172 | },
173 |
174 | eslint: {
175 | target: ['app/static/js/*.js']
176 | },
177 | jsbeautifier: {
178 | dist: {
179 | src: ['app/static/js/*.js', 'app/static/*.html', 'app/templates/*.html', 'app/static/css/*.css',
180 | 'test/*.js'
181 | ],
182 | options: {
183 | config: ".jsbeautifyrc",
184 | mode: "VERIFY_ONLY"
185 | },
186 | },
187 |
188 | format: {
189 | src: ['app/static/js/*.js', 'app/static/*.html', 'app/templates/*.html', 'app/static/css/*.css',
190 | 'test/*.js', 'Gruntfile.js'
191 | ],
192 | options: {
193 | config: ".jsbeautifyrc",
194 | mode: "VERIFY_AND_WRITE"
195 | },
196 | },
197 | },
198 | shell: {
199 | npm_test_mocha: {
200 | command: 'npm run test',
201 | }
202 | }
203 | });
204 |
205 | grunt.loadNpmTasks('grunt-svgmin');
206 | grunt.loadNpmTasks('grunt-contrib-cssmin');
207 | grunt.loadNpmTasks('grunt-contrib-uglify-es');
208 | grunt.loadNpmTasks('grunt-string-replace');
209 | grunt.loadNpmTasks('grunt-contrib-htmlmin');
210 | grunt.loadNpmTasks('grunt-contrib-copy');
211 | grunt.loadNpmTasks('grunt-contrib-imagemin');
212 | grunt.loadNpmTasks('grunt-eslint');
213 | grunt.loadNpmTasks('grunt-jsbeautifier');
214 | grunt.loadNpmTasks('grunt-shell');
215 |
216 | grunt.registerTask('default', [ /*'jsbeautifier:dist',*/ 'eslint', /*'shell:npm_test_mocha',*/ 'svgmin', 'cssmin',
217 | 'uglify',
218 | 'string-replace', 'htmlmin', 'copy', 'imagemin'
219 | ]);
220 | grunt.registerTask('format', ['jsbeautifier:format']);
221 | };
222 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Andreas Fertig
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # C++ Insights - Web Front-End
2 |
3 | [](https://opensource.org/licenses/MIT)
4 | [](https://github.com/andreasfertig/cppinsights-web/releases)
5 | [](https://github.com/andreasfertig/cppinsights-web/actions/)
6 | [](https://codecov.io/gh/andreasfertig/cppinsights-web)
7 | [](https://cppinsights.io)
8 |
9 |
10 |
11 | [cppinsights.io](https://cppinsights.io/) is the web front-end of C++ Insights.
12 |
13 |
14 | ```
15 | pip3 install --user virtualenv
16 | python3 -m virtualenv env
17 | source env/bin/activate
18 | pip3 install -r requirements.txt
19 |
20 | python3 -m pytest test.py
21 | pytest test.py --cov=app
22 | pytest test.py --cov=app --cov-report=html
23 | ```
24 |
25 | ## Short Links
26 |
27 | There is now a short-link option. Via the usual way to obtain a link there is now a
28 | 'Request Short-Link' button. This requests a new short link from the back-end.
29 |
30 | Short links in C++ Insights capture the currently selected options and the code entered. They do not preserve the
31 | C++ Insights version used at the time of creation. This implies that the resulting transformation can change over time.
32 |
33 | What a user gets back is a part of a SHA1 hash from all the captured values. This is also stored in the database and
34 | used during lookup to prevent having the same code multiple times in the database.
35 |
36 | For future use, the link creation time is also stored.
37 |
38 | Please be advised to not store any confidential data in a short-link! You have no guarantees that at some point I will
39 | not loose the database (security breach, misshapening...).
40 |
41 | The primary use for short-links should be easy sharing (twitter, stack overflow, etc.). There are some cases of large code samples which do not work
42 | with long links. This is a secondary issue addressed by short-links.
43 |
44 | ## Other logos
45 |
46 | [Compiler Explorer](https://raw.githubusercontent.com/mattgodbolt/compiler-explorer-image/master/logo/icon/CompilerExplorer%20Logo%20Icon%20SVG.svg)
47 | [QuickBench](https://github.com/FredTingaud/quick-bench-front-end/blob/master/public/ico/favicon-32x32.png), SVG version
48 | from [here](https://github.com/mattgodbolt/compiler-explorer/blob/master/views/resources/quickbench.svg)
49 |
--------------------------------------------------------------------------------
/app/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 | #
4 | # C++ Insights Web, copyright (c) by Andreas Fertig
5 | # Distributed under an MIT license. See /LICENSE
6 |
7 | from flask import Flask, make_response, render_template, request, send_from_directory, jsonify, url_for, redirect
8 | from werkzeug.exceptions import HTTPException
9 | import subprocess
10 | import base64
11 | import os
12 | import tempfile
13 | import sqlite3
14 | import hashlib
15 | from datetime import date, datetime
16 | #------------------------------------------------------------------------------
17 |
18 | app = Flask(__name__, static_folder='static', static_url_path='')
19 | app.config['MAX_CONTENT_LENGTH'] = 50 * 1024 # 50 kB
20 | app.config['USE_DOCKER'] = True # Set to False to use a local binary.
21 | app.config['USE_SUDO'] = True
22 | app.config['USE_MAC'] = False
23 | #------------------------------------------------------------------------------
24 |
25 | @app.route('/favicon.ico')
26 | def favicon():
27 | return send_from_directory(os.path.join(app.root_path, 'static'),
28 | 'favicon.ico', mimetype='image/vnd.microsoft.icon')
29 | #------------------------------------------------------------------------------
30 |
31 | def getDefaultStandard():
32 | return 'cpp20'
33 | #------------------------------------------------------------------------------
34 |
35 | def getCommunityEventFileName():
36 | return 'communityevent.txt'
37 | #------------------------------------------------------------------------------
38 |
39 | def getCommunityEvent():
40 | fName = getCommunityEventFileName()
41 |
42 | link = None
43 | title = None
44 |
45 | if os.path.exists(fName):
46 | communityEvents = open(fName, 'r').read()
47 |
48 | if 0 != len(communityEvents):
49 | link, title = communityEvents.split(';')
50 |
51 | return link, title
52 | #------------------------------------------------------------------------------
53 |
54 | def runDocker(code, insightsOptions, cppStd, versionOnly=False):
55 | fd, fileName = tempfile.mkstemp(suffix='.cpp')
56 | try:
57 | if not versionOnly:
58 | with os.fdopen(fd, 'wb') as tmp:
59 | # write the data into the file
60 | tmp.write(code.encode('utf-8'))
61 |
62 | # FIXME (2018-04-28): workaround as docker user cannot read file without this
63 | os.chmod(fileName, 436)
64 |
65 | fileParam = []
66 | if not versionOnly:
67 | basePath = ''
68 |
69 | # on mac for docker file must be under /private where we also find var
70 | if app.config['USE_MAC']:
71 | basePath = '/private'
72 |
73 | fileParam = [ '-v', '%s%s:/home/insights/insights.cpp' %(basePath, fileName) ]
74 |
75 | if app.config['USE_DOCKER']:
76 | # Prepend the command line with sudo
77 | if app.config['USE_SUDO']:
78 | cmd = [ 'sudo', '-u', 'pfes' ]
79 | else:
80 | cmd = []
81 |
82 | cmd.extend([ 'docker', 'run', '--net=none' ])
83 | cmd.extend(fileParam)
84 | cmd.extend(['--rm', '-i', 'cppinsights-container'])
85 | else:
86 | cmd = ['insights', fileName]
87 |
88 |
89 | if None != insightsOptions:
90 | cmd.extend(insightsOptions)
91 |
92 | if (None != insightsOptions or None != cppStd) or versionOnly:
93 | cmd.append('--')
94 |
95 | if None != cppStd:
96 | cppStd = cppStd.replace('2a', '20') # for transitioning
97 | cmd.append(cppStd)
98 |
99 | p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
100 |
101 | stdout, stderr = p.communicate(timeout=20)
102 | returncode = p.returncode
103 |
104 | finally:
105 | os.remove(fileName)
106 |
107 | return stdout.decode('utf-8'), stderr.decode('utf-8'), returncode
108 | #------------------------------------------------------------------------------
109 |
110 | def buildResponse(code, stdout, stderr, insightsOptions, errCode, twcard=False, desc=''):
111 | if twcard:
112 | twdesc = code[: 100]
113 |
114 | if desc:
115 | desc = ' - ' + desc
116 |
117 | communitylink, communitytitle = getCommunityEvent()
118 | communityEventHide = ''
119 |
120 | if None == communitylink or None == communitytitle:
121 | communityEventHide = 'nocommunityevent'
122 |
123 | selectedInsightsOptions = getInsightsSelections(insightsOptions)
124 | response = make_response(render_template('index.html', **locals()))
125 |
126 | return response, errCode
127 | #------------------------------------------------------------------------------
128 |
129 | def error_handler(errCode, code):
130 | stderr = 'Failed'
131 | stdout = '// Sorry, but your request failed due to a server error:\n// %s\n\n// Sorry for the inconvenience.\n// Please feel free to report this error.' %(errCode)
132 |
133 | return buildResponse('// ' + code, stdout, stderr, [] , errCode)
134 | #------------------------------------------------------------------------------
135 |
136 | def getSupportedOptions():
137 | opts = [ {'desc': 'C++ Standard' , 'flag' : '', 'name' : 'C++ Standard', 'selected' : False, 'label' : True, 'single' : False , 'ccopt' : False, 'cppStd' : False },
138 | {'desc': 'cpp98' , 'flag' : '-std=c++98', 'name' : 'C++ 98', 'selected' : False, 'label' : False, 'single' : True , 'ccopt' : True, 'cppStd' : True },
139 | {'desc': 'cpp11' , 'flag' : '-std=c++11', 'name' : 'C++ 11', 'selected' : False, 'label' : False, 'single' : True , 'ccopt' : True, 'cppStd' : True },
140 | {'desc': 'cpp14' , 'flag' : '-std=c++14', 'name' : 'C++ 14', 'selected' : False, 'label' : False, 'single' : True , 'ccopt' : True, 'cppStd' : True },
141 | {'desc': 'cpp17' , 'flag' : '-std=c++17', 'name' : 'C++ 17', 'selected' : False, 'label' : False, 'single' : True , 'ccopt' : True, 'cppStd' : True },
142 | {'desc': 'cpp20' , 'flag' : '-std=c++20', 'name' : 'C++ 20', 'selected' : False, 'label' : False, 'single' : True , 'ccopt' : True, 'cppStd' : True },
143 | {'desc': 'cpp23' , 'flag' : '-std=c++23', 'name' : 'C++ 23', 'selected' : False, 'label' : False, 'single' : True , 'ccopt' : True, 'cppStd' : True },
144 | {'desc': 'cpp2c' , 'flag' : '-std=c++2c', 'name' : 'C++ 2c', 'selected' : False, 'label' : False, 'single' : True , 'ccopt' : True, 'cppStd' : True },
145 | {'desc': 'Alternative Styles' , 'flag' : '', 'name' : 'Alternative Styles', 'selected' : False, 'label' : True, 'single' : False , 'ccopt' : False, 'cppStd' : False },
146 | {'desc': 'alt-syntax-for' , 'flag' : '-alt-syntax-for', 'name' : 'for-loops as while-loops', 'selected' : False, 'label' : False, 'single' : False , 'ccopt' : False, 'cppStd' : False },
147 | {'desc': 'alt-syntax-subscription' , 'flag' : '-alt-syntax-subscription', 'name' : 'array subscription', 'selected' : False, 'label' : False, 'single' : False , 'ccopt' : False, 'cppStd' : False },
148 | {'desc': 'More Transformations' , 'flag' : '', 'name' : 'More Transformations', 'selected' : False, 'label' : True, 'single' : False , 'ccopt' : False, 'cppStd' : False },
149 | {'desc': 'all-implicit-casts' , 'flag' : '-show-all-implicit-casts', 'name' : 'Show all implicit casts', 'selected' : False, 'label' : False, 'single' : False , 'ccopt' : False, 'cppStd' : False },
150 | {'desc': 'show-all-callexpr-template-parameters' , 'flag' : '-show-all-callexpr-template-parameters', 'name' : 'Show all template parameters of a CallExpr', 'selected' : False, 'label' : False, 'single' : False , 'ccopt' : False, 'cppStd' : False },
151 | {'desc': 'use-libcpp' , 'flag' : '-use-libc++', 'name' : 'Use libc++', 'selected' : False, 'label' : False, 'single' : False , 'ccopt' : False, 'cppStd' : False },
152 | {'desc': 'edu-show-initlist' , 'flag' : '-edu-show-initlist', 'name' : 'Transform std::initializer_list', 'selected' : False, 'label' : False, 'single' : False , 'ccopt' : False, 'cppStd' : False },
153 | {'desc': 'edu-show-noexcept' , 'flag' : '-edu-show-noexcept', 'name' : 'Show noexcept internals', 'selected' : False, 'label' : False, 'single' : False , 'ccopt' : False, 'cppStd' : False },
154 | {'desc': 'edu-show-padding' , 'flag' : '-edu-show-padding', 'name' : 'Show padding information', 'selected' : False, 'label' : False, 'single' : False , 'ccopt' : False, 'cppStd' : False },
155 | {'desc': 'edu-show-coroutines' , 'flag' : '-edu-show-coroutine-transformation', 'name' : 'Show coroutine transformation', 'selected' : False, 'label' : False, 'single' : False , 'ccopt' : False, 'cppStd' : False },
156 | {'desc': 'edu-show-cfront' , 'flag' : '-edu-show-cfront', 'name' : 'Show C++ to C transformation', 'selected' : False, 'label' : False, 'single' : False , 'ccopt' : False, 'cppStd' : False },
157 | {'desc': 'edu-show-lifetime' , 'flag' : '-edu-show-lifetime', 'name' : 'Show object lifetime', 'selected' : False, 'label' : False, 'single' : False , 'ccopt' : False, 'cppStd' : False },
158 | ]
159 |
160 | return opts
161 | #------------------------------------------------------------------------------
162 |
163 | def getInsightsSelections(selected):
164 | stdSelections = getSupportedOptions()
165 | bHaveCppStd = False
166 |
167 | for opt in selected:
168 | for e in stdSelections:
169 | if opt == e['desc']:
170 | e['selected'] = True
171 |
172 | if True == e['cppStd']:
173 | bHaveCppStd = True
174 |
175 | # check that at least one C++ standard is selected, if not insert the default.
176 | if not bHaveCppStd:
177 | for e in stdSelections:
178 | if e['desc'] == getDefaultStandard():
179 | e['selected'] = True
180 |
181 | return stdSelections
182 | #------------------------------------------------------------------------------
183 |
184 | def render(insightsOptions, code, twcard=False, desc=''):
185 | stdout = ''
186 | stderr = ''
187 |
188 | return buildResponse(code, stdout, stderr, insightsOptions, 200, twcard, desc)
189 | #------------------------------------------------------------------------------
190 |
191 | def getValidInsightsOptions(options):
192 | validOpts = getSupportedOptions()
193 | opts = []
194 |
195 | for opt in options:
196 | for e in validOpts:
197 | if e['desc'] == opt:
198 | opts.append(e)
199 |
200 | return opts
201 | #------------------------------------------------------------------------------
202 |
203 | @app.route("/api/v1/transform", methods=['POST'])
204 | def api():
205 | content = request.json
206 | code = content['code']
207 | options = getValidInsightsOptions(content['insightsOptions'])
208 |
209 | insightsOptions = [opt['flag'] for opt in options if not opt['ccopt']]
210 | cppStd = [opt['flag'] for opt in options if opt['ccopt']]
211 |
212 | if 0 == len(cppStd):
213 | cppStd = [ getValidInsightsOptions([getDefaultStandard()])[0]['flag'] ]
214 |
215 | stdout, stderr, returncode = runDocker(code, insightsOptions, cppStd[0])
216 |
217 | if (None == stderr) or ('' == stderr):
218 | stderr = 'Insights exited with result code: %d' %(returncode)
219 |
220 | if returncode:
221 | stdout = 'Compilation failed!'
222 |
223 | resp = {}
224 | resp['returncode'] = returncode
225 | resp['stdout'] = stdout
226 | resp['stderr'] = stderr
227 |
228 |
229 | return jsonify(resp)
230 | #------------------------------------------------------------------------------
231 |
232 | @app.route("/api/v1/getshortlink", methods=['POST'])
233 | def getShortLink():
234 | content = request.json
235 | code = content['code']
236 | desc = content['desc']
237 | rev = content['rev']
238 | cppStd = content['std']
239 | options = '|'.join(content['options'])
240 | toolId = 1 # reserved in case we will have a windows container later.
241 |
242 | code = decodeCode(code)
243 | desc = decodeCode(desc)
244 |
245 | # check for missing code
246 | if None == code:
247 | resp = {}
248 | resp['returncode'] = 2
249 | resp['shortlink'] = 'No source'
250 |
251 | return jsonify(resp)
252 |
253 | # limit content length
254 | elif len(code) > 1000000: # 1 MB
255 | resp = {}
256 | resp['returncode'] = 1
257 | resp['shortlink'] = 'Source too long'
258 |
259 | return jsonify(resp)
260 |
261 | conn = sqlite3.connect(getDbName())
262 |
263 | c = conn.cursor()
264 |
265 | # Create the structure if it does not exist
266 | c.execute('''CREATE TABLE IF NOT EXISTS shortened (id INTEGER primary key autoincrement, toolid INTEGER, code TEXT NOT NULL, desc TEXT NOT NULL, rev text NOT NULL, cppStd TEXT NOT NULL, options TEXT NOT NULL, short TEXT NOT NULL, create_at TIMESTAMP)''')
267 |
268 | # Check if there is already an entry for this combination
269 | cur = c.execute('SELECT short FROM shortened WHERE code=? AND rev=? AND cppStd=? AND options=?', (code, rev, cppStd, options,))
270 |
271 | rv = cur.fetchone()
272 |
273 | # Pack all together for the unique hash
274 | full = code + rev + cppStd + options
275 | hash_object = hashlib.sha1(full.encode('utf-8'))
276 | hex_dig = hash_object.hexdigest()
277 | surl = hex_dig[ : 8]
278 | retVal = 0
279 |
280 | if None == rv:
281 | now = datetime.now()
282 | c.execute('INSERT INTO shortened (toolid, code, desc, rev, cppStd, options, short, create_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)', (toolId, code, desc, rev, cppStd, options, surl, now,))
283 | else:
284 | retVal = 1
285 | surl = rv[0]
286 |
287 |
288 | # Commit and close
289 | conn.commit()
290 | conn.close()
291 |
292 | resp = {}
293 | resp['returncode'] = retVal
294 | resp['shortlink'] = '/s/%s' %(surl)
295 |
296 | return jsonify(resp)
297 | #------------------------------------------------------------------------------
298 |
299 | def getVersionInfo():
300 | stdout, stderr, returncode = runDocker('', None, None, True)
301 |
302 | if (None == stderr) or ('' == stderr):
303 | stderr = 'Insights exited with result code: %d' %(returncode)
304 |
305 | if returncode:
306 | stdout = 'Compilation failed!'
307 |
308 | resp = {}
309 | resp['returncode'] = returncode
310 | resp['stdout'] = stdout
311 | resp['stderr'] = stderr
312 |
313 | dockerImage = 'cppinsights-container'
314 | if app.config['USE_DOCKER']:
315 | p = subprocess.Popen(['docker', 'images', '--filter=reference=%s' %(dockerImage), '--format', '{{.ID}} {{.CreatedAt}}'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
316 |
317 | stdout, stderr = p.communicate(timeout=20)
318 | stdout = stdout.decode('utf-8')
319 | returncode = p.returncode
320 | else:
321 | stdout = 'Docker not used'
322 |
323 | resp['stdout'] += '\nDocker image "%s" info: ' %(dockerImage) + stdout + '\n'
324 |
325 | return resp
326 | #------------------------------------------------------------------------------
327 |
328 | @app.route("/api/v1/version", methods=['GET'])
329 | def apiversion():
330 | resp = getVersionInfo()
331 |
332 | return jsonify(resp)
333 | #------------------------------------------------------------------------------
334 |
335 | @app.route("/version", methods=['GET'])
336 | def version():
337 | resp = getVersionInfo()
338 |
339 | version = resp['stdout']
340 | version = version.replace('\n', '')
341 |
342 | response = make_response(render_template('version.html', **locals()))
343 |
344 | return response
345 | #------------------------------------------------------------------------------
346 |
347 | def getDbName():
348 | return 'urls.db'
349 | #------------------------------------------------------------------------------
350 |
351 | def decodeCode(code):
352 | try:
353 | # keep this in mind if, we get a incorrect length base64 string
354 | #code = code + '=' * (-len(code) % 4)
355 | # XXX: somehow we get a corrupt base64 string
356 | code = code.replace(' ', '+')
357 |
358 | # base 64 decode
359 | return base64.b64decode(code).decode('utf-8')
360 |
361 | except:
362 | print(repr(code))
363 |
364 | return None
365 | #------------------------------------------------------------------------------
366 |
367 | @app.route("/", methods=['GET'])
368 | def index():
369 | code = ''
370 |
371 | return render([getDefaultStandard()], code)
372 | #------------------------------------------------------------------------------
373 |
374 | def proccessLink(code, desc, cppStd, insightsOptions, rev):
375 | if not rev or '1.0' != rev:
376 | return error_handler(404, 'The revision of the link is invalid.')
377 |
378 | return render(insightsOptions, code, twcard=True, desc=desc)
379 | #------------------------------------------------------------------------------
380 |
381 | @app.route("/lnk", methods=['GET', 'POST'])
382 | def lnk():
383 | code = request.args.get('code', '')
384 | rev = request.args.get('rev', '')
385 | cppStd = request.args.get('std', None)
386 |
387 | rawInsightsOptions = request.args.get('insightsOptions', '')
388 | insightsOptions = rawInsightsOptions.split(',')
389 |
390 | # If this is an old link it has 'std' set. In this case use it.
391 | if None != cppStd:
392 | insightsOptions.append(cppStd)
393 |
394 | if code:
395 | code = decodeCode(code)
396 |
397 | if None == code:
398 | code = ''
399 |
400 | return proccessLink(code, '', cppStd, insightsOptions, rev)
401 | #------------------------------------------------------------------------------
402 |
403 | @app.route("/s/ ")
404 | def slnk(link):
405 | conn = sqlite3.connect(getDbName())
406 | c = conn.cursor()
407 |
408 | cur = c.execute('SELECT code, desc, rev, cppStd, options FROM shortened WHERE short = ?', (link,))
409 |
410 | rv = cur.fetchone()
411 |
412 | conn.close()
413 |
414 | if None == rv:
415 | return error_handler(404, 'There is no such link.')
416 |
417 | code = rv[0]
418 | desc = rv[1]
419 | rev = rv[2]
420 | cppStd = rv[3]
421 | rawInsightsOptions = rv[4]
422 | insightsOptions = rawInsightsOptions.split('|')
423 |
424 | return proccessLink(code, desc, cppStd, insightsOptions, rev)
425 | #------------------------------------------------------------------------------
426 |
427 |
428 | @app.errorhandler(404)
429 | def page_not_found(e):
430 | # print(request.path)
431 | # return redirect("/", code=302)
432 | return render_template('404.html'), 404
433 | #------------------------------------------------------------------------------
434 |
435 | @app.errorhandler(413)
436 | def request_to_large(e):
437 | return error_handler(413, '')
438 | #------------------------------------------------------------------------------
439 |
440 | @app.errorhandler(Exception)
441 | def other_errors(e):
442 | code = request.form.get('code', '')
443 | ecode = 500
444 |
445 | print(e)
446 |
447 | if isinstance(e, HTTPException):
448 | ecode = e.code
449 |
450 | return error_handler(ecode, code)
451 | #------------------------------------------------------------------------------
452 |
453 | def getApp():
454 | return app
455 | #------------------------------------------------------------------------------
456 |
457 |
458 | if __name__ == "__main__":
459 | app.run(host='0.0.0.0')
460 | #------------------------------------------------------------------------------
461 |
462 |
--------------------------------------------------------------------------------
/app/static/16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andreasfertig/cppinsights-web/13b1b4886e5037313c9a8957332aead088c27795/app/static/16.png
--------------------------------------------------------------------------------
/app/static/32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andreasfertig/cppinsights-web/13b1b4886e5037313c9a8957332aead088c27795/app/static/32.png
--------------------------------------------------------------------------------
/app/static/about.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | C++ Insights
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | Home
33 | About
34 |
35 | Policies
36 |
37 | Examples
38 | Settings
39 |
40 |
41 |
42 |
43 |
44 |
45 |
49 |
50 |
51 |
52 |
53 |
54 | About
55 |
56 | C++ Insights is a clang -based tool which
57 | does a source to source transformation. Its goal is to make things visible, which normally and intentionally
58 | happen behind the scenes. It's about the magic the compiler does for us to make things work. Or looking through
59 | the classes of a compiler.
60 |
61 | Some time ago, I started looking into some new things we got with C++11, C++14, C++17 and C++20. Amazing
62 | things like
63 | lambdas, range-based for-loops, and structured bindings. I put it together in a talk. You can find the slides
65 | and a video online.
66 |
67 | However, all that research and some of my training and teaching got me to start thinking about how it would be
68 | if we
69 | could see
70 | with the eyes of the compiler. Sure, there is an AST-dump, at least for clang. With tools like Compiler Explorer , we can see what code the compiler generates from a C++
72 | source snippet. However, what we see is assembler. Neither the AST nor the Compiler
73 | Explorer output is in the language I write code, and therefore I'm most familiar with. Plus, when
74 | teaching
75 | students C++ showing an AST and explaining that it is all there was not quite satisfying for me.
76 |
77 | I started to write a clang -based tool able to transform
78 | a
79 | range-based for-loop into the compiler-internal version. Then, I did the same for structured bindings and
80 | lambdas. In the end, I ended up doing a lot more as initially planned. It shows where operators are
81 | invoked,
82 | places in which the compiler does some casting. C++ Insights is able to deduce the type behind
83 | auto
or decltype
. The goal is to produce compilable code. However, this is not
84 | possible
85 | in all places.
86 |
87 | Still, there is work to do.
88 |
89 | I do not claim to get all the things right. This is just the initial version of C++ Insights I
90 | consider good enough to hand
91 | it to the public. Also, keep in mind that it is solely based on clang and my understanding of C++ and the AST.
92 |
93 | You can see, for example, the transformation of a lambda ,
94 | range-based
95 | for-loop , or auto .
96 | Of course, you can transform any other C++ snippet.
97 |
98 | For those who like videos, there is a C++ Insights series on Youtube . If you have topics you like me to speak
100 | about, please reach out to me.
101 |
102 | The version information of the C++ Insights version running on this website can be found here: https://cppinsights.io/version .
103 | You can find the source of the web front-end
104 | and
105 | the tool C++ Insights on Github.
106 | If you like to support the project, consider submitting
107 | a patch. Another alternative is to become a Patreon
108 | supporter.
109 | Contact: andy at cppinsights.io
110 |
111 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
--------------------------------------------------------------------------------
/app/static/cm/Readme.md:
--------------------------------------------------------------------------------
1 | This is a third-party component and not covered by the license of the C++ Insights project.
2 |
--------------------------------------------------------------------------------
/app/static/cm/active-line.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: http://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 | var WRAP_CLASS = "CodeMirror-activeline";
14 | var BACK_CLASS = "CodeMirror-activeline-background";
15 | var GUTT_CLASS = "CodeMirror-activeline-gutter";
16 |
17 | CodeMirror.defineOption("styleActiveLine", false, function(cm, val, old) {
18 | var prev = old == CodeMirror.Init ? false : old;
19 | if (val == prev) return
20 | if (prev) {
21 | cm.off("beforeSelectionChange", selectionChange);
22 | clearActiveLines(cm);
23 | delete cm.state.activeLines;
24 | }
25 | if (val) {
26 | cm.state.activeLines = [];
27 | updateActiveLines(cm, cm.listSelections());
28 | cm.on("beforeSelectionChange", selectionChange);
29 | }
30 | });
31 |
32 | function clearActiveLines(cm) {
33 | for (var i = 0; i < cm.state.activeLines.length; i++) {
34 | cm.removeLineClass(cm.state.activeLines[i], "wrap", WRAP_CLASS);
35 | cm.removeLineClass(cm.state.activeLines[i], "background", BACK_CLASS);
36 | cm.removeLineClass(cm.state.activeLines[i], "gutter", GUTT_CLASS);
37 | }
38 | }
39 |
40 | function sameArray(a, b) {
41 | if (a.length != b.length) return false;
42 | for (var i = 0; i < a.length; i++)
43 | if (a[i] != b[i]) return false;
44 | return true;
45 | }
46 |
47 | function updateActiveLines(cm, ranges) {
48 | var active = [];
49 | for (var i = 0; i < ranges.length; i++) {
50 | var range = ranges[i];
51 | var option = cm.getOption("styleActiveLine");
52 | if (typeof option == "object" && option.nonEmpty ? range.anchor.line != range.head.line : !range.empty())
53 | continue
54 | var line = cm.getLineHandleVisualStart(range.head.line);
55 | if (active[active.length - 1] != line) active.push(line);
56 | }
57 | if (sameArray(cm.state.activeLines, active)) return;
58 | cm.operation(function() {
59 | clearActiveLines(cm);
60 | for (var i = 0; i < active.length; i++) {
61 | cm.addLineClass(active[i], "wrap", WRAP_CLASS);
62 | cm.addLineClass(active[i], "background", BACK_CLASS);
63 | cm.addLineClass(active[i], "gutter", GUTT_CLASS);
64 | }
65 | cm.state.activeLines = active;
66 | });
67 | }
68 |
69 | function selectionChange(cm, sel) {
70 | updateActiveLines(cm, sel.ranges);
71 | }
72 | });
73 |
--------------------------------------------------------------------------------
/app/static/cm/codemirror.css:
--------------------------------------------------------------------------------
1 | /* BASICS */
2 |
3 | .CodeMirror {
4 | /* Set height, width, borders, and global font properties here */
5 | font-family: monospace;
6 | height: 300px;
7 | color: black;
8 | direction: ltr;
9 | }
10 |
11 | /* PADDING */
12 |
13 | .CodeMirror-lines {
14 | padding: 4px 0; /* Vertical padding around content */
15 | }
16 | .CodeMirror pre {
17 | padding: 0 4px; /* Horizontal padding of content */
18 | }
19 |
20 | .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
21 | background-color: white; /* The little square between H and V scrollbars */
22 | }
23 |
24 | /* GUTTER */
25 |
26 | .CodeMirror-gutters {
27 | border-right: 1px solid #ddd;
28 | background-color: #f7f7f7;
29 | white-space: nowrap;
30 | }
31 | .CodeMirror-linenumbers {}
32 | .CodeMirror-linenumber {
33 | padding: 0 3px 0 5px;
34 | min-width: 20px;
35 | text-align: right;
36 | color: #999;
37 | white-space: nowrap;
38 | }
39 |
40 | .CodeMirror-guttermarker { color: black; }
41 | .CodeMirror-guttermarker-subtle { color: #999; }
42 |
43 | /* CURSOR */
44 |
45 | .CodeMirror-cursor {
46 | border-left: 1px solid black;
47 | border-right: none;
48 | width: 0;
49 | }
50 | /* Shown when moving in bi-directional text */
51 | .CodeMirror div.CodeMirror-secondarycursor {
52 | border-left: 1px solid silver;
53 | }
54 | .cm-fat-cursor .CodeMirror-cursor {
55 | width: auto;
56 | border: 0 !important;
57 | background: #7e7;
58 | }
59 | .cm-fat-cursor div.CodeMirror-cursors {
60 | z-index: 1;
61 | }
62 | .cm-fat-cursor-mark {
63 | background-color: rgba(20, 255, 20, 0.5);
64 | -webkit-animation: blink 1.06s steps(1) infinite;
65 | -moz-animation: blink 1.06s steps(1) infinite;
66 | animation: blink 1.06s steps(1) infinite;
67 | }
68 | .cm-animate-fat-cursor {
69 | width: auto;
70 | border: 0;
71 | -webkit-animation: blink 1.06s steps(1) infinite;
72 | -moz-animation: blink 1.06s steps(1) infinite;
73 | animation: blink 1.06s steps(1) infinite;
74 | background-color: #7e7;
75 | }
76 | @-moz-keyframes blink {
77 | 0% {}
78 | 50% { background-color: transparent; }
79 | 100% {}
80 | }
81 | @-webkit-keyframes blink {
82 | 0% {}
83 | 50% { background-color: transparent; }
84 | 100% {}
85 | }
86 | @keyframes blink {
87 | 0% {}
88 | 50% { background-color: transparent; }
89 | 100% {}
90 | }
91 |
92 | /* Can style cursor different in overwrite (non-insert) mode */
93 | .CodeMirror-overwrite .CodeMirror-cursor {}
94 |
95 | .cm-tab { display: inline-block; text-decoration: inherit; }
96 |
97 | .CodeMirror-rulers {
98 | position: absolute;
99 | left: 0; right: 0; top: -50px; bottom: -20px;
100 | overflow: hidden;
101 | }
102 | .CodeMirror-ruler {
103 | border-left: 1px solid #ccc;
104 | top: 0; bottom: 0;
105 | position: absolute;
106 | }
107 |
108 | /* DEFAULT THEME */
109 |
110 | .cm-s-default .cm-header {color: blue;}
111 | .cm-s-default .cm-quote {color: #090;}
112 | .cm-negative {color: #d44;}
113 | .cm-positive {color: #292;}
114 | .cm-header, .cm-strong {font-weight: bold;}
115 | .cm-em {font-style: italic;}
116 | .cm-link {text-decoration: underline;}
117 | .cm-strikethrough {text-decoration: line-through;}
118 |
119 | .cm-s-default .cm-keyword {color: #708;}
120 | .cm-s-default .cm-atom {color: #219;}
121 | .cm-s-default .cm-number {color: #164;}
122 | .cm-s-default .cm-def {color: #00f;}
123 | .cm-s-default .cm-variable,
124 | .cm-s-default .cm-punctuation,
125 | .cm-s-default .cm-property,
126 | .cm-s-default .cm-operator {}
127 | .cm-s-default .cm-variable-2 {color: #05a;}
128 | .cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;}
129 | .cm-s-default .cm-comment {color: #a50;}
130 | .cm-s-default .cm-string {color: #a11;}
131 | .cm-s-default .cm-string-2 {color: #f50;}
132 | .cm-s-default .cm-meta {color: #555;}
133 | .cm-s-default .cm-qualifier {color: #555;}
134 | .cm-s-default .cm-builtin {color: #30a;}
135 | .cm-s-default .cm-bracket {color: #997;}
136 | .cm-s-default .cm-tag {color: #170;}
137 | .cm-s-default .cm-attribute {color: #00c;}
138 | .cm-s-default .cm-hr {color: #999;}
139 | .cm-s-default .cm-link {color: #00c;}
140 |
141 | .cm-s-default .cm-error {color: #f00;}
142 | .cm-invalidchar {color: #f00;}
143 |
144 | .CodeMirror-composing { border-bottom: 2px solid; }
145 |
146 | /* Default styles for common addons */
147 |
148 | div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;}
149 | div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
150 | .CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
151 | .CodeMirror-activeline-background {background: #e8f2ff;}
152 |
153 | /* STOP */
154 |
155 | /* The rest of this file contains styles related to the mechanics of
156 | the editor. You probably shouldn't touch them. */
157 |
158 | .CodeMirror {
159 | position: relative;
160 | overflow: hidden;
161 | background: white;
162 | }
163 |
164 | .CodeMirror-scroll {
165 | overflow: scroll !important; /* Things will break if this is overridden */
166 | /* 30px is the magic margin used to hide the element's real scrollbars */
167 | /* See overflow: hidden in .CodeMirror */
168 | margin-bottom: -30px; margin-right: -30px;
169 | padding-bottom: 30px;
170 | height: 100%;
171 | outline: none; /* Prevent dragging from highlighting the element */
172 | position: relative;
173 | }
174 | .CodeMirror-sizer {
175 | position: relative;
176 | border-right: 30px solid transparent;
177 | }
178 |
179 | /* The fake, visible scrollbars. Used to force redraw during scrolling
180 | before actual scrolling happens, thus preventing shaking and
181 | flickering artifacts. */
182 | .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
183 | position: absolute;
184 | z-index: 6;
185 | display: none;
186 | }
187 | .CodeMirror-vscrollbar {
188 | right: 0; top: 0;
189 | overflow-x: hidden;
190 | overflow-y: scroll;
191 | }
192 | .CodeMirror-hscrollbar {
193 | bottom: 0; left: 0;
194 | overflow-y: hidden;
195 | overflow-x: scroll;
196 | }
197 | .CodeMirror-scrollbar-filler {
198 | right: 0; bottom: 0;
199 | }
200 | .CodeMirror-gutter-filler {
201 | left: 0; bottom: 0;
202 | }
203 |
204 | .CodeMirror-gutters {
205 | position: absolute; left: 0; top: 0;
206 | min-height: 100%;
207 | z-index: 3;
208 | }
209 | .CodeMirror-gutter {
210 | white-space: normal;
211 | height: 100%;
212 | display: inline-block;
213 | vertical-align: top;
214 | margin-bottom: -30px;
215 | }
216 | .CodeMirror-gutter-wrapper {
217 | position: absolute;
218 | z-index: 4;
219 | background: none !important;
220 | border: none !important;
221 | }
222 | .CodeMirror-gutter-background {
223 | position: absolute;
224 | top: 0; bottom: 0;
225 | z-index: 4;
226 | }
227 | .CodeMirror-gutter-elt {
228 | position: absolute;
229 | cursor: default;
230 | z-index: 4;
231 | }
232 | .CodeMirror-gutter-wrapper ::selection { background-color: transparent }
233 | .CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent }
234 |
235 | .CodeMirror-lines {
236 | cursor: text;
237 | min-height: 1px; /* prevents collapsing before first draw */
238 | }
239 | .CodeMirror pre {
240 | /* Reset some styles that the rest of the page might have set */
241 | -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
242 | border-width: 0;
243 | background: transparent;
244 | font-family: inherit;
245 | font-size: inherit;
246 | margin: 0;
247 | white-space: pre;
248 | word-wrap: normal;
249 | line-height: inherit;
250 | color: inherit;
251 | z-index: 2;
252 | position: relative;
253 | overflow: visible;
254 | -webkit-tap-highlight-color: transparent;
255 | -webkit-font-variant-ligatures: contextual;
256 | font-variant-ligatures: contextual;
257 | }
258 | .CodeMirror-wrap pre {
259 | word-wrap: break-word;
260 | white-space: pre-wrap;
261 | word-break: normal;
262 | }
263 |
264 | .CodeMirror-linebackground {
265 | position: absolute;
266 | left: 0; right: 0; top: 0; bottom: 0;
267 | z-index: 0;
268 | }
269 |
270 | .CodeMirror-linewidget {
271 | position: relative;
272 | z-index: 2;
273 | padding: 0.1px; /* Force widget margins to stay inside of the container */
274 | }
275 |
276 | .CodeMirror-widget {}
277 |
278 | .CodeMirror-rtl pre { direction: rtl; }
279 |
280 | .CodeMirror-code {
281 | outline: none;
282 | }
283 |
284 | /* Force content-box sizing for the elements where we expect it */
285 | .CodeMirror-scroll,
286 | .CodeMirror-sizer,
287 | .CodeMirror-gutter,
288 | .CodeMirror-gutters,
289 | .CodeMirror-linenumber {
290 | -moz-box-sizing: content-box;
291 | box-sizing: content-box;
292 | }
293 |
294 | .CodeMirror-measure {
295 | position: absolute;
296 | width: 100%;
297 | height: 0;
298 | overflow: hidden;
299 | visibility: hidden;
300 | }
301 |
302 | .CodeMirror-cursor {
303 | position: absolute;
304 | pointer-events: none;
305 | }
306 | .CodeMirror-measure pre { position: static; }
307 |
308 | div.CodeMirror-cursors {
309 | visibility: hidden;
310 | position: relative;
311 | z-index: 3;
312 | }
313 | div.CodeMirror-dragcursors {
314 | visibility: visible;
315 | }
316 |
317 | .CodeMirror-focused div.CodeMirror-cursors {
318 | visibility: visible;
319 | }
320 |
321 | .CodeMirror-selected { background: #d9d9d9; }
322 | .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
323 | .CodeMirror-crosshair { cursor: crosshair; }
324 |
325 | .cm-searching {
326 | background-color: #ffa;
327 | background-color: rgba(255, 255, 0, .4);
328 | }
329 |
330 | /* Used to force a border model for a node */
331 | .cm-force-border { padding-right: .1px; }
332 |
333 | @media print {
334 | /* Hide the cursor when printing */
335 | .CodeMirror div.CodeMirror-cursors {
336 | visibility: hidden;
337 | }
338 | }
339 |
340 | /* See issue #2901 */
341 | .cm-tab-wrap-hack:after { content: ''; }
342 |
343 | /* Help users use markselection to safely style text background */
344 | span.CodeMirror-selectedtext { background: none; }
345 |
--------------------------------------------------------------------------------
/app/static/cm/matchbrackets.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: http://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | var ie_lt8 = /MSIE \d/.test(navigator.userAgent) &&
13 | (document.documentMode == null || document.documentMode < 8);
14 |
15 | var Pos = CodeMirror.Pos;
16 |
17 | var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"};
18 |
19 | function findMatchingBracket(cm, where, config) {
20 | var line = cm.getLineHandle(where.line), pos = where.ch - 1;
21 | var afterCursor = config && config.afterCursor
22 | if (afterCursor == null)
23 | afterCursor = /(^| )cm-fat-cursor($| )/.test(cm.getWrapperElement().className)
24 |
25 | // A cursor is defined as between two characters, but in in vim command mode
26 | // (i.e. not insert mode), the cursor is visually represented as a
27 | // highlighted box on top of the 2nd character. Otherwise, we allow matches
28 | // from before or after the cursor.
29 | var match = (!afterCursor && pos >= 0 && matching[line.text.charAt(pos)]) ||
30 | matching[line.text.charAt(++pos)];
31 | if (!match) return null;
32 | var dir = match.charAt(1) == ">" ? 1 : -1;
33 | if (config && config.strict && (dir > 0) != (pos == where.ch)) return null;
34 | var style = cm.getTokenTypeAt(Pos(where.line, pos + 1));
35 |
36 | var found = scanForBracket(cm, Pos(where.line, pos + (dir > 0 ? 1 : 0)), dir, style || null, config);
37 | if (found == null) return null;
38 | return {from: Pos(where.line, pos), to: found && found.pos,
39 | match: found && found.ch == match.charAt(0), forward: dir > 0};
40 | }
41 |
42 | // bracketRegex is used to specify which type of bracket to scan
43 | // should be a regexp, e.g. /[[\]]/
44 | //
45 | // Note: If "where" is on an open bracket, then this bracket is ignored.
46 | //
47 | // Returns false when no bracket was found, null when it reached
48 | // maxScanLines and gave up
49 | function scanForBracket(cm, where, dir, style, config) {
50 | var maxScanLen = (config && config.maxScanLineLength) || 10000;
51 | var maxScanLines = (config && config.maxScanLines) || 1000;
52 |
53 | var stack = [];
54 | var re = config && config.bracketRegex ? config.bracketRegex : /[(){}[\]]/;
55 | var lineEnd = dir > 0 ? Math.min(where.line + maxScanLines, cm.lastLine() + 1)
56 | : Math.max(cm.firstLine() - 1, where.line - maxScanLines);
57 | for (var lineNo = where.line; lineNo != lineEnd; lineNo += dir) {
58 | var line = cm.getLine(lineNo);
59 | if (!line) continue;
60 | var pos = dir > 0 ? 0 : line.length - 1, end = dir > 0 ? line.length : -1;
61 | if (line.length > maxScanLen) continue;
62 | if (lineNo == where.line) pos = where.ch - (dir < 0 ? 1 : 0);
63 | for (; pos != end; pos += dir) {
64 | var ch = line.charAt(pos);
65 | if (re.test(ch) && (style === undefined || cm.getTokenTypeAt(Pos(lineNo, pos + 1)) == style)) {
66 | var match = matching[ch];
67 | if ((match.charAt(1) == ">") == (dir > 0)) stack.push(ch);
68 | else if (!stack.length) return {pos: Pos(lineNo, pos), ch: ch};
69 | else stack.pop();
70 | }
71 | }
72 | }
73 | return lineNo - dir == (dir > 0 ? cm.lastLine() : cm.firstLine()) ? false : null;
74 | }
75 |
76 | function matchBrackets(cm, autoclear, config) {
77 | // Disable brace matching in long lines, since it'll cause hugely slow updates
78 | var maxHighlightLen = cm.state.matchBrackets.maxHighlightLineLength || 1000;
79 | var marks = [], ranges = cm.listSelections();
80 | for (var i = 0; i < ranges.length; i++) {
81 | var match = ranges[i].empty() && findMatchingBracket(cm, ranges[i].head, config);
82 | if (match && cm.getLine(match.from.line).length <= maxHighlightLen) {
83 | var style = match.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket";
84 | marks.push(cm.markText(match.from, Pos(match.from.line, match.from.ch + 1), {className: style}));
85 | if (match.to && cm.getLine(match.to.line).length <= maxHighlightLen)
86 | marks.push(cm.markText(match.to, Pos(match.to.line, match.to.ch + 1), {className: style}));
87 | }
88 | }
89 |
90 | if (marks.length) {
91 | // Kludge to work around the IE bug from issue #1193, where text
92 | // input stops going to the textare whever this fires.
93 | if (ie_lt8 && cm.state.focused) cm.focus();
94 |
95 | var clear = function() {
96 | cm.operation(function() {
97 | for (var i = 0; i < marks.length; i++) marks[i].clear();
98 | });
99 | };
100 | if (autoclear) setTimeout(clear, 800);
101 | else return clear;
102 | }
103 | }
104 |
105 | function doMatchBrackets(cm) {
106 | cm.operation(function() {
107 | if (cm.state.matchBrackets.currentlyHighlighted) {
108 | cm.state.matchBrackets.currentlyHighlighted();
109 | cm.state.matchBrackets.currentlyHighlighted = null;
110 | }
111 | cm.state.matchBrackets.currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets);
112 | });
113 | }
114 |
115 | CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) {
116 | if (old && old != CodeMirror.Init) {
117 | cm.off("cursorActivity", doMatchBrackets);
118 | if (cm.state.matchBrackets && cm.state.matchBrackets.currentlyHighlighted) {
119 | cm.state.matchBrackets.currentlyHighlighted();
120 | cm.state.matchBrackets.currentlyHighlighted = null;
121 | }
122 | }
123 | if (val) {
124 | cm.state.matchBrackets = typeof val == "object" ? val : {};
125 | cm.on("cursorActivity", doMatchBrackets);
126 | }
127 | });
128 |
129 | CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);});
130 | CodeMirror.defineExtension("findMatchingBracket", function(pos, config, oldConfig){
131 | // Backwards-compatibility kludge
132 | if (oldConfig || typeof config == "boolean") {
133 | if (!oldConfig) {
134 | config = config ? {strict: true} : null
135 | } else {
136 | oldConfig.strict = config
137 | config = oldConfig
138 | }
139 | }
140 | return findMatchingBracket(this, pos, config)
141 | });
142 | CodeMirror.defineExtension("scanForBracket", function(pos, dir, style, config){
143 | return scanForBracket(this, pos, dir, style, config);
144 | });
145 | });
146 |
--------------------------------------------------------------------------------
/app/static/cm/show-hint.css:
--------------------------------------------------------------------------------
1 | .CodeMirror-hints {
2 | position: absolute;
3 | z-index: 10;
4 | overflow: hidden;
5 | list-style: none;
6 |
7 | margin: 0;
8 | padding: 2px;
9 |
10 | -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
11 | -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
12 | box-shadow: 2px 3px 5px rgba(0,0,0,.2);
13 | border-radius: 3px;
14 | border: 1px solid silver;
15 |
16 | background: white;
17 | font-size: 90%;
18 | font-family: monospace;
19 |
20 | max-height: 20em;
21 | overflow-y: auto;
22 | }
23 |
24 | .CodeMirror-hint {
25 | margin: 0;
26 | padding: 0 4px;
27 | border-radius: 2px;
28 | white-space: pre;
29 | color: black;
30 | cursor: pointer;
31 | }
32 |
33 | li.CodeMirror-hint-active {
34 | background: #08f;
35 | color: white;
36 | }
37 |
--------------------------------------------------------------------------------
/app/static/cm/show-hint.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: http://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 |
14 | var HINT_ELEMENT_CLASS = "CodeMirror-hint";
15 | var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active";
16 |
17 | // This is the old interface, kept around for now to stay
18 | // backwards-compatible.
19 | CodeMirror.showHint = function(cm, getHints, options) {
20 | if (!getHints) return cm.showHint(options);
21 | if (options && options.async) getHints.async = true;
22 | var newOpts = {hint: getHints};
23 | if (options) for (var prop in options) newOpts[prop] = options[prop];
24 | return cm.showHint(newOpts);
25 | };
26 |
27 | CodeMirror.defineExtension("showHint", function(options) {
28 | options = parseOptions(this, this.getCursor("start"), options);
29 | var selections = this.listSelections()
30 | if (selections.length > 1) return;
31 | // By default, don't allow completion when something is selected.
32 | // A hint function can have a `supportsSelection` property to
33 | // indicate that it can handle selections.
34 | if (this.somethingSelected()) {
35 | if (!options.hint.supportsSelection) return;
36 | // Don't try with cross-line selections
37 | for (var i = 0; i < selections.length; i++)
38 | if (selections[i].head.line != selections[i].anchor.line) return;
39 | }
40 |
41 | if (this.state.completionActive) this.state.completionActive.close();
42 | var completion = this.state.completionActive = new Completion(this, options);
43 | if (!completion.options.hint) return;
44 |
45 | CodeMirror.signal(this, "startCompletion", this);
46 | completion.update(true);
47 | });
48 |
49 | function Completion(cm, options) {
50 | this.cm = cm;
51 | this.options = options;
52 | this.widget = null;
53 | this.debounce = 0;
54 | this.tick = 0;
55 | this.startPos = this.cm.getCursor("start");
56 | this.startLen = this.cm.getLine(this.startPos.line).length - this.cm.getSelection().length;
57 |
58 | var self = this;
59 | cm.on("cursorActivity", this.activityFunc = function() { self.cursorActivity(); });
60 | }
61 |
62 | var requestAnimationFrame = window.requestAnimationFrame || function(fn) {
63 | return setTimeout(fn, 1000/60);
64 | };
65 | var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout;
66 |
67 | Completion.prototype = {
68 | close: function() {
69 | if (!this.active()) return;
70 | this.cm.state.completionActive = null;
71 | this.tick = null;
72 | this.cm.off("cursorActivity", this.activityFunc);
73 |
74 | if (this.widget && this.data) CodeMirror.signal(this.data, "close");
75 | if (this.widget) this.widget.close();
76 | CodeMirror.signal(this.cm, "endCompletion", this.cm);
77 | },
78 |
79 | active: function() {
80 | return this.cm.state.completionActive == this;
81 | },
82 |
83 | pick: function(data, i) {
84 | var completion = data.list[i];
85 | if (completion.hint) completion.hint(this.cm, data, completion);
86 | else this.cm.replaceRange(getText(completion), completion.from || data.from,
87 | completion.to || data.to, "complete");
88 | CodeMirror.signal(data, "pick", completion);
89 | this.close();
90 | },
91 |
92 | cursorActivity: function() {
93 | if (this.debounce) {
94 | cancelAnimationFrame(this.debounce);
95 | this.debounce = 0;
96 | }
97 |
98 | var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line);
99 | if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch ||
100 | pos.ch < this.startPos.ch || this.cm.somethingSelected() ||
101 | (pos.ch && this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) {
102 | this.close();
103 | } else {
104 | var self = this;
105 | this.debounce = requestAnimationFrame(function() {self.update();});
106 | if (this.widget) this.widget.disable();
107 | }
108 | },
109 |
110 | update: function(first) {
111 | if (this.tick == null) return
112 | var self = this, myTick = ++this.tick
113 | fetchHints(this.options.hint, this.cm, this.options, function(data) {
114 | if (self.tick == myTick) self.finishUpdate(data, first)
115 | })
116 | },
117 |
118 | finishUpdate: function(data, first) {
119 | if (this.data) CodeMirror.signal(this.data, "update");
120 |
121 | var picked = (this.widget && this.widget.picked) || (first && this.options.completeSingle);
122 | if (this.widget) this.widget.close();
123 |
124 | this.data = data;
125 |
126 | if (data && data.list.length) {
127 | if (picked && data.list.length == 1) {
128 | this.pick(data, 0);
129 | } else {
130 | this.widget = new Widget(this, data);
131 | CodeMirror.signal(data, "shown");
132 | }
133 | }
134 | }
135 | };
136 |
137 | function parseOptions(cm, pos, options) {
138 | var editor = cm.options.hintOptions;
139 | var out = {};
140 | for (var prop in defaultOptions) out[prop] = defaultOptions[prop];
141 | if (editor) for (var prop in editor)
142 | if (editor[prop] !== undefined) out[prop] = editor[prop];
143 | if (options) for (var prop in options)
144 | if (options[prop] !== undefined) out[prop] = options[prop];
145 | if (out.hint.resolve) out.hint = out.hint.resolve(cm, pos)
146 | return out;
147 | }
148 |
149 | function getText(completion) {
150 | if (typeof completion == "string") return completion;
151 | else return completion.text;
152 | }
153 |
154 | function buildKeyMap(completion, handle) {
155 | var baseMap = {
156 | Up: function() {handle.moveFocus(-1);},
157 | Down: function() {handle.moveFocus(1);},
158 | PageUp: function() {handle.moveFocus(-handle.menuSize() + 1, true);},
159 | PageDown: function() {handle.moveFocus(handle.menuSize() - 1, true);},
160 | Home: function() {handle.setFocus(0);},
161 | End: function() {handle.setFocus(handle.length - 1);},
162 | Enter: handle.pick,
163 | Tab: handle.pick,
164 | Esc: handle.close
165 | };
166 | var custom = completion.options.customKeys;
167 | var ourMap = custom ? {} : baseMap;
168 | function addBinding(key, val) {
169 | var bound;
170 | if (typeof val != "string")
171 | bound = function(cm) { return val(cm, handle); };
172 | // This mechanism is deprecated
173 | else if (baseMap.hasOwnProperty(val))
174 | bound = baseMap[val];
175 | else
176 | bound = val;
177 | ourMap[key] = bound;
178 | }
179 | if (custom)
180 | for (var key in custom) if (custom.hasOwnProperty(key))
181 | addBinding(key, custom[key]);
182 | var extra = completion.options.extraKeys;
183 | if (extra)
184 | for (var key in extra) if (extra.hasOwnProperty(key))
185 | addBinding(key, extra[key]);
186 | return ourMap;
187 | }
188 |
189 | function getHintElement(hintsElement, el) {
190 | while (el && el != hintsElement) {
191 | if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el;
192 | el = el.parentNode;
193 | }
194 | }
195 |
196 | function Widget(completion, data) {
197 | this.completion = completion;
198 | this.data = data;
199 | this.picked = false;
200 | var widget = this, cm = completion.cm;
201 |
202 | var hints = this.hints = document.createElement("ul");
203 | hints.className = "CodeMirror-hints";
204 | this.selectedHint = data.selectedHint || 0;
205 |
206 | var completions = data.list;
207 | for (var i = 0; i < completions.length; ++i) {
208 | var elt = hints.appendChild(document.createElement("li")), cur = completions[i];
209 | var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS);
210 | if (cur.className != null) className = cur.className + " " + className;
211 | elt.className = className;
212 | if (cur.render) cur.render(elt, data, cur);
213 | else elt.appendChild(document.createTextNode(cur.displayText || getText(cur)));
214 | elt.hintId = i;
215 | }
216 |
217 | var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null);
218 | var left = pos.left, top = pos.bottom, below = true;
219 | hints.style.left = left + "px";
220 | hints.style.top = top + "px";
221 | // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor.
222 | var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth);
223 | var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight);
224 | (completion.options.container || document.body).appendChild(hints);
225 | var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH;
226 | var scrolls = hints.scrollHeight > hints.clientHeight + 1
227 | var startScroll = cm.getScrollInfo();
228 |
229 | if (overlapY > 0) {
230 | var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top);
231 | if (curTop - height > 0) { // Fits above cursor
232 | hints.style.top = (top = pos.top - height) + "px";
233 | below = false;
234 | } else if (height > winH) {
235 | hints.style.height = (winH - 5) + "px";
236 | hints.style.top = (top = pos.bottom - box.top) + "px";
237 | var cursor = cm.getCursor();
238 | if (data.from.ch != cursor.ch) {
239 | pos = cm.cursorCoords(cursor);
240 | hints.style.left = (left = pos.left) + "px";
241 | box = hints.getBoundingClientRect();
242 | }
243 | }
244 | }
245 | var overlapX = box.right - winW;
246 | if (overlapX > 0) {
247 | if (box.right - box.left > winW) {
248 | hints.style.width = (winW - 5) + "px";
249 | overlapX -= (box.right - box.left) - winW;
250 | }
251 | hints.style.left = (left = pos.left - overlapX) + "px";
252 | }
253 | if (scrolls) for (var node = hints.firstChild; node; node = node.nextSibling)
254 | node.style.paddingRight = cm.display.nativeBarWidth + "px"
255 |
256 | cm.addKeyMap(this.keyMap = buildKeyMap(completion, {
257 | moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); },
258 | setFocus: function(n) { widget.changeActive(n); },
259 | menuSize: function() { return widget.screenAmount(); },
260 | length: completions.length,
261 | close: function() { completion.close(); },
262 | pick: function() { widget.pick(); },
263 | data: data
264 | }));
265 |
266 | if (completion.options.closeOnUnfocus) {
267 | var closingOnBlur;
268 | cm.on("blur", this.onBlur = function() { closingOnBlur = setTimeout(function() { completion.close(); }, 100); });
269 | cm.on("focus", this.onFocus = function() { clearTimeout(closingOnBlur); });
270 | }
271 |
272 | cm.on("scroll", this.onScroll = function() {
273 | var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect();
274 | var newTop = top + startScroll.top - curScroll.top;
275 | var point = newTop - (window.pageYOffset || (document.documentElement || document.body).scrollTop);
276 | if (!below) point += hints.offsetHeight;
277 | if (point <= editor.top || point >= editor.bottom) return completion.close();
278 | hints.style.top = newTop + "px";
279 | hints.style.left = (left + startScroll.left - curScroll.left) + "px";
280 | });
281 |
282 | CodeMirror.on(hints, "dblclick", function(e) {
283 | var t = getHintElement(hints, e.target || e.srcElement);
284 | if (t && t.hintId != null) {widget.changeActive(t.hintId); widget.pick();}
285 | });
286 |
287 | CodeMirror.on(hints, "click", function(e) {
288 | var t = getHintElement(hints, e.target || e.srcElement);
289 | if (t && t.hintId != null) {
290 | widget.changeActive(t.hintId);
291 | if (completion.options.completeOnSingleClick) widget.pick();
292 | }
293 | });
294 |
295 | CodeMirror.on(hints, "mousedown", function() {
296 | setTimeout(function(){cm.focus();}, 20);
297 | });
298 |
299 | CodeMirror.signal(data, "select", completions[this.selectedHint], hints.childNodes[this.selectedHint]);
300 | return true;
301 | }
302 |
303 | Widget.prototype = {
304 | close: function() {
305 | if (this.completion.widget != this) return;
306 | this.completion.widget = null;
307 | this.hints.parentNode.removeChild(this.hints);
308 | this.completion.cm.removeKeyMap(this.keyMap);
309 |
310 | var cm = this.completion.cm;
311 | if (this.completion.options.closeOnUnfocus) {
312 | cm.off("blur", this.onBlur);
313 | cm.off("focus", this.onFocus);
314 | }
315 | cm.off("scroll", this.onScroll);
316 | },
317 |
318 | disable: function() {
319 | this.completion.cm.removeKeyMap(this.keyMap);
320 | var widget = this;
321 | this.keyMap = {Enter: function() { widget.picked = true; }};
322 | this.completion.cm.addKeyMap(this.keyMap);
323 | },
324 |
325 | pick: function() {
326 | this.completion.pick(this.data, this.selectedHint);
327 | },
328 |
329 | changeActive: function(i, avoidWrap) {
330 | if (i >= this.data.list.length)
331 | i = avoidWrap ? this.data.list.length - 1 : 0;
332 | else if (i < 0)
333 | i = avoidWrap ? 0 : this.data.list.length - 1;
334 | if (this.selectedHint == i) return;
335 | var node = this.hints.childNodes[this.selectedHint];
336 | node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, "");
337 | node = this.hints.childNodes[this.selectedHint = i];
338 | node.className += " " + ACTIVE_HINT_ELEMENT_CLASS;
339 | if (node.offsetTop < this.hints.scrollTop)
340 | this.hints.scrollTop = node.offsetTop - 3;
341 | else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight)
342 | this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3;
343 | CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node);
344 | },
345 |
346 | screenAmount: function() {
347 | return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1;
348 | }
349 | };
350 |
351 | function applicableHelpers(cm, helpers) {
352 | if (!cm.somethingSelected()) return helpers
353 | var result = []
354 | for (var i = 0; i < helpers.length; i++)
355 | if (helpers[i].supportsSelection) result.push(helpers[i])
356 | return result
357 | }
358 |
359 | function fetchHints(hint, cm, options, callback) {
360 | if (hint.async) {
361 | hint(cm, callback, options)
362 | } else {
363 | var result = hint(cm, options)
364 | if (result && result.then) result.then(callback)
365 | else callback(result)
366 | }
367 | }
368 |
369 | function resolveAutoHints(cm, pos) {
370 | var helpers = cm.getHelpers(pos, "hint"), words
371 | if (helpers.length) {
372 | var resolved = function(cm, callback, options) {
373 | var app = applicableHelpers(cm, helpers);
374 | function run(i) {
375 | if (i == app.length) return callback(null)
376 | fetchHints(app[i], cm, options, function(result) {
377 | if (result && result.list.length > 0) callback(result)
378 | else run(i + 1)
379 | })
380 | }
381 | run(0)
382 | }
383 | resolved.async = true
384 | resolved.supportsSelection = true
385 | return resolved
386 | } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) {
387 | return function(cm) { return CodeMirror.hint.fromList(cm, {words: words}) }
388 | } else if (CodeMirror.hint.anyword) {
389 | return function(cm, options) { return CodeMirror.hint.anyword(cm, options) }
390 | } else {
391 | return function() {}
392 | }
393 | }
394 |
395 | CodeMirror.registerHelper("hint", "auto", {
396 | resolve: resolveAutoHints
397 | });
398 |
399 | CodeMirror.registerHelper("hint", "fromList", function(cm, options) {
400 | var cur = cm.getCursor(), token = cm.getTokenAt(cur);
401 | var to = CodeMirror.Pos(cur.line, token.end);
402 | if (token.string && /\w/.test(token.string[token.string.length - 1])) {
403 | var term = token.string, from = CodeMirror.Pos(cur.line, token.start);
404 | } else {
405 | var term = "", from = to;
406 | }
407 | var found = [];
408 | for (var i = 0; i < options.words.length; i++) {
409 | var word = options.words[i];
410 | if (word.slice(0, term.length) == term)
411 | found.push(word);
412 | }
413 |
414 | if (found.length) return {list: found, from: from, to: to};
415 | });
416 |
417 | CodeMirror.commands.autocomplete = CodeMirror.showHint;
418 |
419 | var defaultOptions = {
420 | hint: CodeMirror.hint.auto,
421 | completeSingle: true,
422 | alignWithWord: true,
423 | closeCharacters: /[\s()\[\]{};:>,]/,
424 | closeOnUnfocus: true,
425 | completeOnSingleClick: true,
426 | container: null,
427 | customKeys: null,
428 | extraKeys: null
429 | };
430 |
431 | CodeMirror.defineOption("hintOptions", null);
432 | });
433 |
--------------------------------------------------------------------------------
/app/static/cookie-policy.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | C++ Insights - Cookie Policy
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | Home
33 | About
34 |
35 | Policies
36 |
37 | Examples
38 | Settings
39 |
40 |
41 |
42 |
43 |
44 |
45 |
49 |
50 |
51 |
52 |
53 |
54 | C++ Insights Cookie Policy
55 |
56 | Browsers support the storing and sending back of small text files called "Cookies". These cookie files can be
57 | used (amongst other things) to help to track the usage of a website. See the Mozilla description of cookies
59 | for more details.
60 |
61 | C++ Insights uses a cookie to store current state, such as:
62 |
63 | Current consent status
64 |
65 |
66 |
67 | C++ Insights uses a Local Storage to store current state, such as:
68 |
69 | Your current code
70 | The selected C++ Standard
71 |
72 |
73 |
74 | This information is used to provide a better user experience, it is used at no point to track any user
75 | identifying information. For general privacy information see Privacy Policy
76 |
77 | Note that the consent status cookie is set even if you decline cookies. Otherwise, the website would ask you
78 | all
79 | the time whether to accept cookies. In case, you do not click decline or accept no cookies at all are
80 | stored.
81 |
82 |
83 |
84 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/app/static/css/s.css:
--------------------------------------------------------------------------------
1 | /* C++ Insights Web, copyright (c) by Andreas Fertig
2 | Distributed under an MIT license. See /LICENSE */
3 |
4 | :root {
5 | --cl-main-bg: #fff;
6 | --cl-text: #000;
7 | --cl-text-gray: #333;
8 | --cl-text-light-gray: gray;
9 | --cl-black: #000;
10 | --cl-button: var(--cl-main-bg);
11 | --cl-button-hover: #e6ebf1;
12 | --cl-button-border: rgba(27, 31, 35, 0.2);
13 | --cl-button-border-hover: rgba(27, 31, 35, 0.35);
14 | --cl-button-text: #24292e;
15 |
16 | --cl-link: #0275d8;
17 | --cl-link-hover: #014c8c;
18 |
19 | --cl-button-header: #545353;
20 |
21 | --cl-in-readonly: var(--cl-text-gray);
22 | --cl-in-readonly-selected: var(--cl-in-readonly);
23 | --cl-in-readonly-bg: #f2f2f2;
24 |
25 | --cl-code-bg: var(--cl-main-bg);
26 | --cl-code-selected-line: #e6e6e6;
27 | --cl-code-selection: #a3d0ff;
28 | --cl-code-border: #c5c5c5;
29 | --cl-console-bg: #f4f4f4;
30 | --cl-cursor: var(--cl-text);
31 |
32 | --cl-cm-string: #032f62;
33 | --cl-cm-keyword: #d73a49;
34 | --cl-cm-definition: #6f42c1;
35 | --cl-cm-number: #005cc5;
36 |
37 | --filter-icon-invert: 0%;
38 | --filter-icon-grayscale: 0%;
39 | --filter-logo-brightness: 100%;
40 | }
41 |
42 | @media (prefers-color-scheme: dark) {
43 | /* CSS Code if Dark Mode is active. Keep in sync with "[data-theme="dark"]" */
44 |
45 | :root {
46 | --cl-main-bg: #353839;
47 | --cl-black: #cdcdce;
48 | --cl-text: var(--cl-black);
49 | --cl-text-gray: var(--cl-black);
50 | --cl-text-light-gray: var(--cl-button-text);
51 |
52 | --cl-button: #515354;
53 | --cl-button-hover: var(--cl-main-bg);
54 | --cl-button-border: var(--cl-button);
55 | --cl-button-border-hover: var(--cl-button);
56 | --cl-button-text: #cdcdce;
57 |
58 | --cl-link: #64b2f5;
59 | --cl-link-hover: #87b1d5;
60 |
61 | --cl-button-header: inherit;
62 |
63 | --cl-in-readonly: #5a5c62;
64 | --cl-in-readonly-selected: white;
65 | --cl-in-readonly-bg: #313131;
66 |
67 | --cl-code-bg: #1f1f23;
68 | --cl-code-selected-line: #24252c;
69 | --cl-code-selection: #515b70;
70 | --cl-code-border: #000;
71 | --cl-console-bg: var(--cl-code-bg);
72 | --cl-cursor: var(--cl-text);
73 |
74 | --cl-cm-string: #569cd6;
75 | --cl-cm-keyword: #fb60a2;
76 | --cl-cm-definition: #9874d9;
77 | --cl-cm-number: #b5cea8;
78 |
79 | --filter-icon-invert: 60%;
80 | --filter-icon-grayscale: 100%;
81 | --filter-logo-brightness: 130%;
82 | }
83 | }
84 |
85 | [data-theme="dark"] {
86 | /* copy & paste from above (@media (prefers-color-scheme: dark)) */
87 | --cl-main-bg: #353839;
88 | --cl-black: #cdcdce;
89 | --cl-text: var(--cl-black);
90 | --cl-text-gray: var(--cl-black);
91 | --cl-text-light-gray: var(--cl-button-text);
92 |
93 | --cl-button: #515354;
94 | --cl-button-hover: var(--cl-main-bg);
95 | --cl-button-border: var(--cl-button);
96 | --cl-button-border-hover: var(--cl-button);
97 | --cl-button-text: #cdcdce;
98 |
99 | --cl-link: #64b2f5;
100 | --cl-link-hover: #87b1d5;
101 |
102 | --cl-button-header: inherit;
103 |
104 | --cl-in-readonly: #5a5c62;
105 | --cl-in-readonly-selected: white;
106 | --cl-in-readonly-bg: #313131;
107 |
108 | --cl-code-bg: #1f1f23;
109 | --cl-code-selected-line: #24252c;
110 | --cl-code-selection: #515b70;
111 | --cl-code-border: #000;
112 | --cl-console-bg: var(--cl-code-bg);
113 | --cl-cursor: var(--cl-text);
114 |
115 | --cl-cm-string: #569cd6;
116 | --cl-cm-keyword: #fb60a2;
117 | --cl-cm-definition: #9874d9;
118 | --cl-cm-number: #b5cea8;
119 |
120 | --filter-icon-invert: 60%;
121 | --filter-icon-grayscale: 100%;
122 | --filter-logo-brightness: 130%;
123 |
124 | }
125 |
126 | html {
127 | height: 100%;
128 | }
129 |
130 | body,
131 | html {
132 | margin: 0;
133 | padding: 0;
134 | color: var(--cl-text-gray);
135 | background: var(--cl-main-bg);
136 | font-family: Verdana, Helvetica, Arial, sans-serif;
137 | }
138 |
139 | body {
140 | min-height: 100%;
141 | font-size: initial;
142 | font-weight: 400;
143 | line-height: 1.5;
144 | }
145 |
146 | h1 {
147 | font-size: larger;
148 | }
149 |
150 | input {}
151 |
152 | label {
153 | margin: 0;
154 | }
155 |
156 | button:focus {
157 | outline: none;
158 | }
159 |
160 | main {
161 | display: grid;
162 | margin-left: 10px;
163 | margin-right: 10px;
164 |
165 | grid-template:
166 | "nav nav nav" 41px "srcin vdragbar insights" minmax(60vh, auto) "hdragbar hdragbar hdragbar" 10px "console console console" minmax(0, 150px) / calc(50% - 5px) 10px calc(50% - 5px);
167 | height: 100vh;
168 | }
169 |
170 | #single {
171 | grid-template:
172 | "nav nav" 41px "content content " auto / 100%;
173 | }
174 |
175 | nav {
176 | grid-area: nav;
177 | display: grid;
178 | grid-template:
179 | "controls news about" 41px / max-content minmax(100px, auto) max-content;
180 | align-items: center;
181 | }
182 |
183 | srcin {
184 | grid-area: srcin;
185 | }
186 |
187 | vdragbar {
188 | grid-area: vdragbar;
189 | cursor: col-resize;
190 | }
191 |
192 | hdragbar {
193 | grid-area: hdragbar;
194 | cursor: row-resize;
195 | }
196 |
197 | vdragbar:hover,
198 | hdragbar:hover {
199 | background: var(--cl-console-bg);
200 | }
201 |
202 | insights {
203 | grid-area: insights;
204 | }
205 |
206 | console {
207 | grid-area: console;
208 | }
209 |
210 | info {
211 | grid-area: info;
212 | }
213 |
214 | controls {
215 | grid-area: controls;
216 | }
217 |
218 | news {
219 | grid-area: news;
220 | margin-left: auto;
221 | margin-right: auto;
222 | }
223 |
224 | about {
225 | grid-area: about;
226 | align-self: baseline;
227 | }
228 |
229 | .icon-run,
230 | .icon-save,
231 | .icon-load,
232 | .icon-link,
233 | .icon-twitter {
234 | speak: none;
235 | font-style: normal;
236 | font-weight: normal;
237 | font-variant: normal;
238 | text-transform: none;
239 | line-height: 1;
240 | -webkit-font-smoothing: antialiased;
241 | }
242 |
243 | .icon-run:before,
244 | .icon-run:hover:before,
245 | #active .icon-run:before,
246 | .icon-save:before,
247 | .icon-save:hover:before,
248 | #active .icon-save:before,
249 | .icon-load:before,
250 | .icon-load:hover:before,
251 | #active .icon-load:before,
252 | .icon-link:before,
253 | .icon-link:hover:before,
254 | #active .icon-link:before,
255 | .icon-twitter:before,
256 | .icon-twitter:hover:before,
257 | #active .icon-twitter:before {
258 | content: "";
259 | background-image: url("../img/nav.svg");
260 | width: 16px;
261 | height: 16px;
262 | display: block;
263 | filter: invert(var(--filter-icon-invert));
264 | }
265 |
266 | .btn-group-lg>.btn,
267 | .btn-lg {
268 | font-size: .8em;
269 | }
270 |
271 | .btn-primary:hover,
272 | .ms-choice:hover {
273 | color: var(--cl-text);
274 | background-color: var(--cl-button-hover);
275 | border-color: var(--cl-button-border-hover);
276 | }
277 |
278 | .btn-primary {
279 | color: var(--cl-button-text);
280 | background-color: var(--cl-button);
281 | border: 1px solid var(--cl-button-border);
282 | }
283 |
284 | .btn-group-lg>.btn,
285 | .btn-lg {
286 | height: 32px;
287 | line-height: 32px;
288 | padding-left: 1rem;
289 | padding-right: 1rem;
290 | }
291 |
292 | #cppStd {
293 | padding-left: 0.5rem;
294 | }
295 |
296 | .btn {
297 | transition: initial;
298 | margin-top: 5px;
299 | cursor: pointer;
300 | }
301 |
302 | .btn:focus,
303 | .btn:hover {
304 | text-decoration: none;
305 | outline: none;
306 | }
307 |
308 | .btn-group-lg>.btn,
309 | .btn-lg {
310 | border-radius: .3rem;
311 | }
312 |
313 | .btn {
314 | display: inline-block;
315 | text-align: center;
316 | white-space: nowrap;
317 | vertical-align: middle;
318 | -webkit-user-select: none;
319 | -moz-user-select: none;
320 | -ms-user-select: none;
321 | user-select: none;
322 | -webkit-transition: all .2s ease-in-out;
323 | -o-transition: all .2s ease-in-out;
324 | transition: all .2s ease-in-out;
325 | }
326 |
327 | /* remove standard-styles */
328 | select {
329 | -webkit-appearance: none;
330 | -moz-appearance: none;
331 | appearance: none;
332 | border: none;
333 | border-radius: 0;
334 | font-size: 1em;
335 | /*width: 100%*/
336 | }
337 |
338 | /*
339 | @-moz-document url-prefix() {
340 | select, select:-moz-focusring, select::-moz-focus-inner {
341 | color: transparent !important;
342 | text-shadow: 0 0 0 #000 !important;
343 | background-image: none !important;
344 | border:0;
345 | }
346 | }
347 | */
348 |
349 | /* remove standard-styles */
350 | /*
351 | select {
352 | -webkit-appearance: none;
353 | -moz-appearance: none;
354 | appearance: none;
355 | border:none;
356 | border-radius: 0;
357 | font-size: 1em;
358 | width: 100%;
359 | display: inline-block;
360 | overflow: hidden;
361 | }
362 | */
363 |
364 | [role="button"],
365 | a,
366 | area,
367 | button,
368 | input,
369 | label,
370 | select,
371 | summary,
372 | textarea {
373 | -ms-touch-action: manipulation;
374 | touch-action: manipulation;
375 | }
376 |
377 | *,
378 | ::after,
379 | ::before {
380 | -webkit-box-sizing: inherit;
381 | box-sizing: inherit;
382 | }
383 |
384 | img {
385 | vertical-align: middle;
386 | border-style: none;
387 | }
388 |
389 | #cookie-law {
390 | background-color: lightcyan;
391 | height: 60px;
392 | vertical-align: middle;
393 | margin: 0;
394 | font-size: 0.9em;
395 | line-height: 60px;
396 | padding-left: 10px;
397 | }
398 |
399 | .accept-decline {
400 | width: 20%;
401 | display: inline-block;
402 | float: right;
403 | }
404 |
405 | .btn-decline,
406 | .btn-accept {
407 | width: 50%;
408 | display: block;
409 | height: 60px;
410 | text-align: center;
411 | }
412 |
413 | .btn-accept {
414 | float: right;
415 | background-color: darkturquoise;
416 | }
417 |
418 | .btn-decline {
419 | float: left;
420 | }
421 |
422 | a:focus,
423 | a:hover {
424 | color: var(--cl-link-hover);
425 | text-decoration: underline;
426 | }
427 |
428 | a:active,
429 | a:hover {
430 | outline-width: 0;
431 | }
432 |
433 | a {
434 | background-color: transparent;
435 | color: var(--cl-link);
436 | text-decoration: none;
437 | }
438 |
439 | a.close-cookie-banner,
440 | a.decline-cookie-banner {
441 | display: block;
442 | background-color: turquoise;
443 | height: 60px;
444 | text-align: center;
445 | color: white;
446 | }
447 |
448 | a.decline-cookie-banner {
449 | background-color: lightcyan;
450 | color: black;
451 | }
452 |
453 | a.decline-cookie-banner:focus,
454 | a.decline-cookie-banner:hover,
455 | a.close-cookie-banner:focus,
456 | a.close-cookie-banner:hover {
457 | background-color: darkturquoise;
458 | color: white;
459 | text-decoration: none;
460 | }
461 |
462 | #container {
463 | width: 100%;
464 | margin-left: auto;
465 | margin-right: auto;
466 | }
467 |
468 | #container>div {
469 | margin: auto 1em;
470 | }
471 |
472 | #stdin,
473 | #stdout,
474 | #stderr {
475 | height: 100%;
476 | display: flex;
477 | flex-flow: column;
478 | }
479 |
480 | #stderr-div {
481 | display: flex;
482 | flex-flow: column;
483 | flex-grow: 1;
484 | }
485 |
486 | #stderr button,
487 | #banner button {
488 | border: none;
489 | background: inherit;
490 | margin: 0;
491 | padding: 0;
492 | font-size: small;
493 | color: inherit;
494 | cursor: pointer;
495 | vertical-align: super;
496 | }
497 |
498 | #stderr button {
499 | background-position: center center;
500 | background-repeat: no-repeat;
501 | background-size: 100%;
502 | width: 10px;
503 | height: 10px;
504 | opacity: .5;
505 | }
506 |
507 | #stderr button:hover {
508 | opacity: 1;
509 | }
510 |
511 | #stderr button {
512 | background-image: url("data:image/svg+xml,%3C%3Fxml version='1.0' encoding='UTF-8' standalone='no'%3F%3E%3Csvg xmlns='http://www.w3.org/2000/svg' version='1.1' width='10' height='10' viewBox='0 0 10 10'%3E%3Cg stroke='%23808080' fill='none'%3E%3Cpath d='m0,0 10,0 0,10 -10,0 0,-10'/%3E%3Cpath d='m0,1 10,0' stroke-width='2'/%3E%3C/g%3E%3C/svg%3E%0A");
513 | }
514 |
515 | #stderr .minimized {
516 | background-image: url("data:image/svg+xml,%3C%3Fxml version='1.0' encoding='UTF-8' standalone='no'%3F%3E%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 10 10'%3E%3Cg stroke='%23808080' fill='none'%3E%3Cpath d='m0,10 10,0' stroke-width='3'/%3E%3C/g%3E%3C/svg%3E ");
517 | }
518 |
519 | #lnkdesc {
520 | width: 100%;
521 | height: 30px;
522 | background-color: var(--cl-main-bg);
523 | color: var(--cl-text);
524 | border: 1px solid #ccc;
525 | border-bottom: none;
526 | border-top: none;
527 | }
528 |
529 | #header {
530 | text-align: left;
531 | font-size: 70%;
532 | border-left: 1px dotted var(--cl-black);
533 | padding-left: 10px;
534 | color: var(--cl-text-light-gray);
535 | padding-top: 5px;
536 | }
537 |
538 | #footer {
539 | display: none;
540 | }
541 |
542 | .kt,
543 | .k {
544 | color: #226BAA;
545 | font-weight: bold;
546 | }
547 |
548 | .c1,
549 | .cm {
550 | color: #6666FF;
551 | }
552 |
553 | .s,
554 | .se {
555 | color: #B3793D;
556 | }
557 |
558 | .linenos {
559 | color: #7F7F7F;
560 | }
561 |
562 | .icon-run:before,
563 | .icon-run:hover:before {
564 | background-position: 0px 0;
565 | }
566 |
567 | .icon-save:before,
568 | .icon-save:hover:before {
569 | background-position: 64px 0;
570 | }
571 |
572 | .icon-load:before,
573 | .icon-load:hover:before {
574 | background-position: 48px 0;
575 | }
576 |
577 | .icon-link:before,
578 | .icon-link:hover:before {
579 | background-position: 32px 0;
580 | }
581 |
582 | .icon-twitter:before,
583 | .icon-twitter:hover:before {
584 | background-position: 16px 0;
585 | }
586 |
587 | .CodeMirror {
588 | overflow: hidden;
589 | width: 100%;
590 | border: solid var(--cl-code-border);
591 | border-width: 1px;
592 | flex-grow: 1;
593 | background: var(--cl-code-bg);
594 | }
595 |
596 | .CodeMirror-gutters {
597 | border-right: initial;
598 | background-color: initial;
599 | white-space: nowrap;
600 | }
601 |
602 | .CodeMirror-selected {
603 | background-color: var(--cl-code-selection) !important;
604 | }
605 |
606 | .CodeMirror-focused div.CodeMirror-selected {
607 | background: rgba(255, 255, 255, 0.10);
608 | }
609 |
610 | .CodeMirror-activeline-background {
611 | background: #e8e8e8;
612 | }
613 |
614 | .CodeMirror-line::selection,
615 | .CodeMirror-line>span::selection,
616 | .CodeMirror-line>span>span::selection,
617 | .CodeMirror-activeline-background {
618 | background: var(--cl-code-selected-line);
619 | }
620 |
621 | .CodeMirror-line::-moz-selection,
622 | .CodeMirror-line>span::-moz-selection,
623 | .CodeMirror-line>span>span::-moz-selection {
624 | background: var(--cl-code-selected-line);
625 | }
626 |
627 | .CodeMirror,
628 | .cm-s-default .cm-variable,
629 | .cm-s-default .cm-punctuation,
630 | .cm-s-default .cm-property,
631 | .cm-s-default .cm-operator {
632 | color: var(--cl-text);
633 | }
634 |
635 | .CodeMirror div.CodeMirror-cursor {
636 | border-left: 1px solid var(--cl-cursor);
637 | }
638 |
639 | /*.CodeMirror-selectedtext {
640 | color: white;
641 | }
642 | */
643 |
644 | div.CodeMirror span.CodeMirror-matchingbracket {
645 | color: inherit;
646 | border: var(--cl-text-light-gray);
647 | border-width: thin;
648 | border-style: solid;
649 | }
650 |
651 | .CodeMirror-linenumber {
652 | background-color: var(--cl-code-bg);
653 | }
654 |
655 | .CodeMirror-activeline-gutter .CodeMirror-linenumber {
656 | background: var(--cl-code-selected-line);
657 | }
658 |
659 | /**
660 | * GitHub Gist Theme from https://github.com/LouisBarranqueiro
661 | */
662 |
663 | .cm-s-default .cm-comment,
664 | .c1,
665 | .cm {
666 | color: #6a737d;
667 | }
668 |
669 | .cm-s-default .cm-keyword,
670 | .cm-s-default .cm-meta,
671 | .cm-s-default .cm-type,
672 | .k,
673 | .kt,
674 | .cp,
675 | .cpf {
676 | color: var(--cl-cm-keyword);
677 | }
678 |
679 | .cm-s-default .cm-def,
680 | .nf {
681 | color: var(--cl-cm-definition);
682 | }
683 |
684 | .cm-s-default .cm-number {
685 | color: var(--cl-cm-number);
686 | }
687 |
688 | .cm-s-default .cm-string,
689 | .cm-s-default .cm-atom,
690 | .s,
691 | .se {
692 | color: var(--cl-cm-string);
693 | }
694 |
695 | .k,
696 | .kt {
697 | font-weight: normal;
698 | }
699 |
700 | .shortlink-entry {
701 | border: 1px solid #ddd;
702 | border-radius: 3px;
703 | margin-bottom: 16px;
704 | margin-top: 16px;
705 | margin-bottom: 1.5em;
706 | }
707 |
708 | .shortlink-entry-header {
709 | font-size: 12px;
710 | line-height: 32px;
711 | background-color: #fafbfc;
712 | border-bottom: 1px solid #e1e4e8;
713 | border-top-left-radius: 3px;
714 | border-top-right-radius: 3px;
715 | padding: 5px 10px;
716 | }
717 |
718 | .content {
719 | width: 90%;
720 | margin: auto;
721 | margin-left: auto !important;
722 | margin-right: auto !important;
723 | }
724 |
725 | .stderr .CodeMirror {
726 | height: 100%;
727 | background: var(--cl-console-bg);
728 | color: var(--cl-text);
729 | }
730 |
731 | .logo {
732 | height: 32px;
733 | width: auto;
734 | margin-right: 2em;
735 | filter: brightness(var(--filter-logo-brightness));
736 | }
737 |
738 | .h2,
739 | h2 {
740 | font-size: 0.8rem;
741 | padding: 0;
742 | margin: 0;
743 | font-weight: 600;
744 | color: var(--cl-text-light-gray);
745 | }
746 |
747 | #file-input {
748 | display: none;
749 | }
750 |
751 | .copy-group {
752 | position: relative;
753 | }
754 |
755 | .input-group {
756 | display: table;
757 | }
758 |
759 | .input-group input:first-child,
760 | .input-group-button:first-child .cpybtn {
761 | border-top-right-radius: 0;
762 | border-bottom-right-radius: 0;
763 | }
764 |
765 | .input-group input,
766 | .input-group-button {
767 | display: table-cell;
768 | }
769 |
770 | .input-group input[type="text"] {
771 | min-height: 30px;
772 | padding: 3px 8px;
773 | color: var(--cl-in-readonly);
774 | vertical-align: middle;
775 | background-color: inherit;
776 | border: 1px solid #ccc;
777 | border-right: none;
778 | border-radius: 3px 0 0 0;
779 | -webkit-border-top-right-radius: 0;
780 | -moz-border-top-right-radius: 0;
781 | -webkit-border-bottom-right-radius: 0;
782 | -moz-border-bottom-right-radius: 0;
783 | outline: 0;
784 | box-shadow: inset 0 1px 2px rgba(0, 0, 0, .075);
785 | width: 100%;
786 | }
787 |
788 | .input-group-button:last-child .cpybtn {
789 | margin-left: -1px;
790 | }
791 |
792 | .input-group input:last-child,
793 | .input-group-button:last-child .cpybtn {}
794 |
795 | .input-group-row {
796 | display: table-row;
797 | border-collapse: collapse;
798 | }
799 |
800 | .input-group-url-row {
801 | width: 100%;
802 | border-collapse: collapse;
803 | }
804 |
805 | .cell-left {
806 | float: left;
807 | width: 80%;
808 | }
809 |
810 | .cell-right {
811 | float: right;
812 | width: 20%;
813 | }
814 |
815 | .cpybtn,
816 | .reqslbtn {
817 | padding: 0 8px;
818 | min-height: 30px;
819 | font-weight: 700;
820 | line-height: 20px;
821 | color: #333;
822 | white-space: nowrap;
823 | vertical-align: middle;
824 | cursor: pointer;
825 | background-color: inherit;
826 | /*#eee;*/
827 | /* background-color: var(--cl-button);
828 | */
829 | border: 1px solid #d5d5d5;
830 | border-radius: 0;
831 | border-top-right-radius: 3px;
832 | -webkit-user-select: none;
833 | -moz-user-select: none;
834 | -ms-user-select: none;
835 | user-select: none;
836 | -webkit-appearance: none;
837 | width: 100%;
838 | outline: none;
839 | }
840 |
841 | .reqslbtn {
842 | background-color: #0366d6;
843 | color: white;
844 | width: 100%;
845 | min-height: 42px;
846 | border-radius: 0 0 3px 3px;
847 | }
848 |
849 | .note-text {
850 | font-size: 0.6em;
851 | padding: 10px;
852 | background-color: lavender;
853 | border-bottom-left-radius: 3px;
854 | border-bottom-right-radius: 3px;
855 | }
856 |
857 | .pagination {
858 | font-size: 0.8em;
859 | margin-bottom: 10px;
860 | }
861 |
862 | .dropdown-table {
863 | padding: 5px;
864 | }
865 |
866 | .morebtn {
867 | margin: 0;
868 | padding: 0;
869 | font-size: inherit;
870 | border: none;
871 | margin-top: .8em;
872 | }
873 |
874 | .clip {
875 | margin-top: -3px;
876 | position: relative;
877 | top: 3px;
878 | filter: invert(var(--filter-icon-invert));
879 | }
880 |
881 | .cebutton,
882 | .qbbutton {
883 | position: relative;
884 | top: -2px;
885 | height: 20px;
886 | filter: grayscale(var(--filter-icon-grayscale)) invert(var(--filter-icon-invert));
887 | }
888 |
889 | .cebutton {
890 | height: 23px;
891 | }
892 |
893 | .copyDownDownContent,
894 | .moreDownDownContent {
895 | display: none;
896 | position: absolute;
897 | left: 0px;
898 | background-color: var(--cl-main-bg);
899 | min-width: 230px;
900 | box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
901 | z-index: 10;
902 | box-sizing: border-box;
903 | border-radius: 3px;
904 | border: 1px solid #aaa;
905 | }
906 |
907 | .moreDownDownContent {
908 | min-width: 0;
909 | background-color: var(--cl-main-bg);
910 | -webkit-box-shadow: 0 4px 5px rgba(0, 0, 0, .15);
911 | -moz-box-shadow: 0 4px 5px rgba(0, 0, 0, .15);
912 | box-shadow: 0 4px 5px rgba(0, 0, 0, .15);
913 | padding: 10px;
914 | color: var(--cl-black);
915 | border: 1px solid #aaa;
916 | -webkit-border-radius: 4px;
917 | -moz-border-radius: 4px;
918 | border-radius: 4px;
919 | font-size: .8em;
920 | }
921 |
922 | .btn-parent {
923 | display: inline-block;
924 | }
925 |
926 | .morebtn a {
927 | color: var(--cl-text);
928 | background-color: var(--cl-main-bg);
929 | }
930 |
931 | .morebtn a:focus,
932 | .morebtn a:hover {
933 | text-decoration: none;
934 | }
935 |
936 | .reqslbtn:hover {
937 | background-color: #0059bd;
938 | }
939 |
940 | .cpybtn:hover {
941 | border-color: var(--cl-button-border-hover);
942 | }
943 |
944 | .news {
945 | position: relative;
946 | display: inline-block;
947 | vertical-align: middle;
948 | margin-top: 5px;
949 | }
950 |
951 | #banner {
952 | border: 1px dotted #0275d8;
953 | border-radius: 2px;
954 | padding: 5px 10px 5px 10px;
955 | font-size: small;
956 | }
957 |
958 | .nocommunityevent {
959 | display: none !important;
960 | }
961 |
962 | .button-more>div {
963 | position: absolute;
964 | top: 0;
965 | right: 0;
966 | width: 20px;
967 |
968 | }
969 |
970 | /*
971 | .button-more>div::after {
972 | content: '▼';
973 | color: var(--cl-text-light-gray);
974 | }
975 | */
976 |
977 | #shrtlnkurl {
978 | color: var(--cl-text-light-gray);
979 | }
980 |
981 | #lnkurl::selection {
982 | background: var(--cl-code-selection);
983 | color: var(--cl-in-readonly-selected);
984 | }
985 |
986 | .show {
987 | display: block;
988 | }
989 |
990 | .ms-parent {
991 | display: inline-block;
992 | position: relative;
993 | vertical-align: middle;
994 | margin-top: 5px;
995 | }
996 |
997 | .ms-choice {
998 | display: block;
999 | width: 100%;
1000 | height: 32px;
1001 | line-height: 32px;
1002 | padding: 0;
1003 | overflow: hidden;
1004 | cursor: pointer;
1005 | text-align: left;
1006 | white-space: nowrap;
1007 | text-decoration: none;
1008 | -webkit-border-radius: 4px;
1009 | -moz-border-radius: 4px;
1010 | border-radius: 4px;
1011 | font-size: 0.8em;
1012 | color: var(--cl-button-text);
1013 | background-color: var(--cl-button);
1014 | border: 1px solid var(--cl-button-border);
1015 | }
1016 |
1017 | .ms-choice>span {
1018 | position: absolute;
1019 | top: 0;
1020 | left: 0;
1021 | right: 20px;
1022 | white-space: nowrap;
1023 | overflow: hidden;
1024 | text-overflow: ellipsis;
1025 | display: block;
1026 | padding-left: 8px;
1027 | }
1028 |
1029 | .ms-choice>span.placeholder {}
1030 |
1031 | .ms-choice>div {
1032 | position: absolute;
1033 | top: 0;
1034 | right: 0;
1035 | width: 20px;
1036 | }
1037 |
1038 | .ms-choice>div:after {
1039 | content: '▼';
1040 | color: var(--cl-text-light-gray);
1041 | }
1042 |
1043 | .ms-choice>div.open:after {
1044 | content: '▲';
1045 | color: var(--cl-text-light-gray);
1046 | }
1047 |
1048 | .ms-choice>div.open {}
1049 |
1050 | .ms-drop {
1051 | width: 100%;
1052 | overflow: hidden;
1053 | display: none;
1054 | margin-top: -1px;
1055 | padding: 0;
1056 | position: absolute;
1057 | z-index: 1000;
1058 | background: var(--cl-main-bg);
1059 | color: var(--cl-text);
1060 | border: 1px solid #aaa;
1061 | -webkit-border-radius: 4px;
1062 | -moz-border-radius: 4px;
1063 | border-radius: 4px;
1064 | font-size: .8em;
1065 | }
1066 |
1067 | .ms-drop.bottom {
1068 | top: 100%;
1069 | -webkit-box-shadow: 0 4px 5px rgba(0, 0, 0, .15);
1070 | -moz-box-shadow: 0 4px 5px rgba(0, 0, 0, .15);
1071 | box-shadow: 0 4px 5px rgba(0, 0, 0, .15);
1072 | }
1073 |
1074 | .ms-drop.top {
1075 | bottom: 100%;
1076 | -webkit-box-shadow: 0 -4px 5px rgba(0, 0, 0, .15);
1077 | -moz-box-shadow: 0 -4px 5px rgba(0, 0, 0, .15);
1078 | box-shadow: 0 -4px 5px rgba(0, 0, 0, .15);
1079 | }
1080 |
1081 | .ms-drop ul {
1082 | overflow: auto;
1083 | margin: 0;
1084 | padding: 5px 8px;
1085 | }
1086 |
1087 | .ms-drop ul>li {
1088 | list-style: none;
1089 | display: list-item;
1090 | background-image: none;
1091 | position: static;
1092 | }
1093 |
1094 | .ms-drop ul>li.multiple {
1095 | display: block;
1096 | float: left;
1097 | }
1098 |
1099 | .ms-drop ul>li.group {
1100 | clear: both;
1101 | }
1102 |
1103 | .ms-drop ul>li.multiple label {
1104 | width: 100%;
1105 | display: block;
1106 | white-space: nowrap;
1107 | overflow: hidden;
1108 | text-overflow: ellipsis;
1109 | }
1110 |
1111 | .ms-drop ul>li label {
1112 | font-weight: normal;
1113 | display: block;
1114 | white-space: nowrap;
1115 | }
1116 |
1117 | .ms-drop ul>li label.optgroup {
1118 | font-weight: bold;
1119 | color: var(--cl-button-header);
1120 | }
1121 |
1122 | .ms-drop input[type="checkbox"] {
1123 | vertical-align: middle;
1124 | margin: 5px;
1125 | }
1126 |
1127 | .optgroup input[type="checkbox"] {
1128 | display: none;
1129 | }
1130 |
1131 | .single input[type="checkbox"] {
1132 | -webkit-appearance: radio;
1133 | /* Chrome, Safari, Opera */
1134 | -moz-appearance: radio;
1135 | /* Firefox */
1136 | -ms-appearance: radio;
1137 | /* not currently supported */
1138 | }
1139 |
1140 | .fonts input[type="radio"] {
1141 | display: none;
1142 | }
1143 |
1144 | .fonts input[type="radio"]:checked+span {
1145 | font-weight: bold;
1146 | }
1147 |
1148 | /* settings */
1149 | #settings {
1150 | list-style: none;
1151 | padding-left: 0;
1152 |
1153 | }
1154 |
1155 | #settings label {
1156 | margin-left: .8em;
1157 | }
1158 |
1159 | /* settings */
1160 |
1161 | @media screen and (max-width: 750px) {
1162 | main {
1163 | grid-template:
1164 | "nav nav" max-content "srcin srcin" 100% "vdragbar vdragbar" 0 "insights insights" 100% "hdragbar hdragbar" 0 "console console" 150px / 100%;
1165 |
1166 | }
1167 |
1168 | nav {
1169 | grid-template:
1170 | "controls controls"
1171 | "news news"
1172 | "about about" 100% / 100%;
1173 | }
1174 |
1175 | .logo {
1176 | margin-right: 0;
1177 | }
1178 |
1179 | #header {
1180 | display: none;
1181 | }
1182 |
1183 | #footer {
1184 | clear: both;
1185 | padding-top: 10px;
1186 | text-align: center;
1187 | font-size: 70%;
1188 | display: initial;
1189 | width: 100%;
1190 | color: var(--cl-text-light-gray);
1191 | }
1192 |
1193 | .btn-group-lg>.btn,
1194 | .btn-lg {
1195 | height: 24px;
1196 | line-height: 24px;
1197 | padding-left: 0.5rem;
1198 | padding-right: 0.5rem;
1199 | }
1200 |
1201 | #cppStd {
1202 | padding-left: 0;
1203 | }
1204 |
1205 | .ms-choice {
1206 | height: 24px;
1207 | line-height: 24px;
1208 | padding-left: 0.5rem;
1209 | padding-right: 0.5rem;
1210 | }
1211 |
1212 | .ms-choice>div {
1213 | width: 10px;
1214 | }
1215 |
1216 | .content {
1217 | width: 100%;
1218 | }
1219 | }
1220 |
--------------------------------------------------------------------------------
/app/static/examples.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | C++ Insights
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | Home
33 | About
34 |
35 | Policies
36 |
37 | Examples
38 | Settings
39 |
40 |
41 |
42 |
43 |
44 |
45 |
49 |
50 |
51 |
52 |
53 |
54 | C++ Insights Examples
55 |
56 | Here are some examples to give you an impression what C++ Insights can show you:
57 |
58 | C++11:
59 |
95 |
96 | C++14:
97 |
108 |
109 | C++17:
110 |
116 |
117 | In case, you're missing an important example, feel free to open a pull
118 | request with a modified
119 | examples.html .
120 |
121 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
--------------------------------------------------------------------------------
/app/static/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andreasfertig/cppinsights-web/13b1b4886e5037313c9a8957332aead088c27795/app/static/favicon.ico
--------------------------------------------------------------------------------
/app/static/img/ce.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
9 |
10 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/app/static/img/clb.svg:
--------------------------------------------------------------------------------
1 |
2 |
17 |
19 |
20 |
22 | image/svg+xml
23 |
25 |
26 |
27 |
28 |
30 |
51 |
54 |
59 |
63 |
68 |
71 |
76 |
81 |
82 |
--------------------------------------------------------------------------------
/app/static/img/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/app/static/img/nav-dark.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
19 |
21 |
44 |
46 |
47 |
49 | image/svg+xml
50 |
52 |
53 |
54 |
55 |
56 |
61 |
66 |
70 |
75 |
76 |
80 |
85 |
86 |
89 |
94 |
95 |
98 |
102 |
103 |
107 |
112 |
113 |
114 |
115 |
--------------------------------------------------------------------------------
/app/static/img/nav.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
19 |
21 |
44 |
46 |
47 |
49 | image/svg+xml
50 |
52 |
53 |
54 |
55 |
56 |
61 |
66 |
69 |
73 |
74 |
77 |
81 |
82 |
85 |
89 |
90 |
93 |
97 |
98 |
101 |
105 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/app/static/img/qb.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
9 | Fichier 1
10 |
11 |
12 |
23 |
24 |
38 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/app/static/img/twcard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andreasfertig/cppinsights-web/13b1b4886e5037313c9a8957332aead088c27795/app/static/img/twcard.png
--------------------------------------------------------------------------------
/app/static/js/cookie.js:
--------------------------------------------------------------------------------
1 | /* C++ Insights Web, copyright (c) by Andreas Fertig
2 | Distributed under an MIT license. See /LICENSE */
3 |
4 | var cookieName = 'complianceCookie';
5 |
6 | function createBanner() {
7 | var bodytag = document.getElementsByTagName('body')[0];
8 | var div = document.createElement('div');
9 | div.setAttribute('id', 'cookie-law');
10 | div.innerHTML =
11 | 'This website uses cookies. See cookie policy for more information. ';
12 |
13 | bodytag.insertBefore(div, bodytag.firstChild);
14 | }
15 |
16 | function createCookie(name, value) {
17 | var days = 365;
18 | var date = new Date();
19 | date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
20 | var expires = '; expires=' + date.toGMTString();
21 |
22 | document.cookie = name + '=' + value + expires + '; path=/';
23 | }
24 |
25 | function checkCookie(name) {
26 | var nameEQ = name + '=';
27 | var ca = document.cookie.split(';');
28 |
29 | for (var i = 0; i < ca.length; i++) {
30 | var c = ca[i];
31 | while (c.charAt(0) == ' ') {
32 | c = c.substring(1, c.length);
33 | }
34 |
35 | if (c.indexOf(nameEQ) == 0) {
36 | return c.substring(nameEQ.length, c.length);
37 | }
38 | }
39 |
40 | return null;
41 | }
42 |
43 | function createComplianceCookie(b) {
44 | createCookie(cookieName, b);
45 | }
46 |
47 | function cookieAccept(b) { // eslint-disable-line no-unused-vars
48 | createComplianceCookie(b);
49 |
50 | var element = document.getElementById('cookie-law');
51 | element.parentNode.removeChild(element);
52 | }
53 |
54 | function storageAllowed() { // eslint-disable-line no-unused-vars
55 | return ('true' == checkCookie(cookieName));
56 | }
57 |
58 | function onLoad() { // eslint-disable-line no-unused-vars
59 | if (!checkCookie(cookieName)) {
60 | createBanner();
61 | }
62 | }
63 |
64 | function canUseLocalStorage() {
65 | return window.localStorage && storageAllowed();
66 | }
67 |
68 | function setLocalStorageItem(key, data) { // eslint-disable-line no-unused-vars
69 | if (canUseLocalStorage()) {
70 | window.localStorage.setItem(key, JSON.stringify(data));
71 | }
72 | }
73 |
74 | function getLocalStorageItem(key, deflt) { // eslint-disable-line no-unused-vars
75 | if (canUseLocalStorage()) {
76 | var data = window.localStorage.getItem(key);
77 | if (data) {
78 | return JSON.parse(data);
79 | }
80 | }
81 |
82 | return deflt;
83 | }
84 |
--------------------------------------------------------------------------------
/app/static/js/main.js:
--------------------------------------------------------------------------------
1 | /* C++ Insights Web, copyright (c) by Andreas Fertig
2 | Distributed under an MIT license. See /LICENSE */
3 |
4 | /* global CodeMirror, onLoad, getLocalStorageItem, setLocalStorageItem, canUseLocalStorage */
5 |
6 | var DEFAULT_CPP_STD = 'cpp17';
7 | var DEFAULT_REV = '1.0';
8 |
9 | // load cookies
10 | onLoad();
11 |
12 | var cppEditor = CodeMirror.fromTextArea(document.getElementById('cpp-code'), {
13 | lineNumbers: true,
14 | matchBrackets: true,
15 | styleActiveLine: true,
16 | mode: 'text/x-c++src'
17 | });
18 |
19 | cppEditor.focus();
20 | var insightsOptions = [DEFAULT_CPP_STD];
21 | var code = cppEditor.getValue();
22 |
23 | function setStandard(std) {
24 | var selected = $('#insightsOptions').multipleSelect('getSelects', 'value');
25 |
26 | var filtered = selected.filter(function(value, index, arr) { // eslint-disable-line no-unused-vars
27 | return !value.startsWith('cpp');
28 | });
29 |
30 | filtered.push(std);
31 |
32 | $('#insightsOptions').multipleSelect('setSelects', filtered);
33 | }
34 |
35 | $('#insightsOptions').multipleSelect({
36 | placeholder: 'C++ Insights Options',
37 | selectAll: false,
38 | onClick: function(opt) {
39 | if (opt.value.startsWith('cpp')) {
40 | setStandard(opt.value);
41 | }
42 | },
43 | onOptgroupClick: function(group) {
44 | if ('C++ Standard' == group.label) {
45 | setStandard(DEFAULT_CPP_STD);
46 | }
47 | },
48 | });
49 |
50 | function changeFontSize(value) {
51 | var elCode = document.getElementById('stdin');
52 | elCode.style.fontSize = value;
53 | var elStdOut = document.getElementById('stdout');
54 | elStdOut.style.fontSize = value;
55 | var elStdErr = document.getElementById('stderr');
56 | elStdErr.style.fontSize = value;
57 | }
58 |
59 | $('#fontSizer').multipleSelect({
60 | placeholder: 'A+',
61 | selectAll: false,
62 | single: true,
63 | onClick: function(opt) {
64 |
65 | changeFontSize(opt.value);
66 |
67 | $('#fontSizer').multipleSelect('setSelects', opt);
68 |
69 | setLocalStorageItem('fontSize', opt.value);
70 | },
71 | });
72 | // check if the current url contains '/lnk' which means that we opened a link. In that case do not load the values from
73 | // local storage.
74 | function isLink() {
75 | return (window.location.href.indexOf('/lnk') > -1) || (window.location.href.indexOf('/s') > -1);
76 | }
77 |
78 | // If this is a link add a keydown listener to the cppEditor and remove the link, if the code is changed.
79 | if (isLink()) {
80 | cppEditor.on('keydown', function(instance, event) { // eslint-disable-line no-unused-vars
81 | if (isLink()) {
82 | history.pushState(null, null, '/');
83 | }
84 |
85 | });
86 | }
87 |
88 | if (canUseLocalStorage() && !isLink()) {
89 | if (!cppEditor.getValue()) {
90 | insightsOptions = window.localStorage.getItem('insightsOptions');
91 |
92 | if (insightsOptions) {
93 | insightsOptions = JSON.parse(insightsOptions);
94 | }
95 |
96 | code = window.localStorage.getItem('code');
97 | if (code) {
98 | code = JSON.parse(code);
99 | }
100 | }
101 | }
102 |
103 | if (!code) {
104 | insightsOptions = [DEFAULT_CPP_STD];
105 | code =
106 | '#include \n\nint main()\n{\n const char arr[10]{2,4,6,8};\n\n for(const char& c : arr)\n {\n printf("c=%c\\n", c);\n }\n}';
107 |
108 | }
109 |
110 | //try {
111 | if (!isLink()) {
112 | $('#insightsOptions').multipleSelect('setSelects', insightsOptions);
113 | }
114 |
115 | var DEFAULT_FONT_SIZE = getLocalStorageItem('fontSize', 'initial');
116 |
117 | $('#fontSizer').multipleSelect('setSelects', [DEFAULT_FONT_SIZE]);
118 | changeFontSize(DEFAULT_FONT_SIZE);
119 |
120 | displayContents(code);
121 | //} catch (e) {
122 | // hm
123 | //}
124 |
125 | var mac = CodeMirror.keyMap.default == CodeMirror.keyMap.macDefault;
126 | CodeMirror.keyMap.default[(mac ? 'Cmd' : 'Ctrl') + '-Space'] = 'autocomplete';
127 | var cppOutEditor = CodeMirror.fromTextArea(document.getElementById(
128 | 'cpp-code-out'), { // eslint-disable-line no-unused-vars
129 | lineNumbers: true,
130 | matchBrackets: true,
131 | styleActiveLine: true,
132 | readOnly: true,
133 | mode: 'text/x-c++src'
134 | });
135 | var stdErrEditor = CodeMirror.fromTextArea(document.getElementById(
136 | 'stderr-out'), { // eslint-disable-line no-unused-vars
137 | lineNumbers: false,
138 | readOnly: true,
139 | mode: 'shell'
140 | });
141 |
142 | function readSingleFile(e) {
143 | var file = e.target.files[0];
144 | if (!file) {
145 | return;
146 | }
147 | var reader = new FileReader();
148 | reader.onload = function(e) {
149 | var contents = e.target.result;
150 | displayContents(contents);
151 | };
152 | reader.readAsText(file);
153 | }
154 |
155 | function displayContents(contents) {
156 | cppEditor.setValue(contents);
157 | }
158 |
159 | document.querySelector('.button-upload')
160 | .addEventListener('click', function(event) {
161 | event.preventDefault();
162 | document.getElementById('file-input').click();
163 | });
164 |
165 | document.getElementById('file-input')
166 | .addEventListener('change', readSingleFile);
167 |
168 | document.querySelector('.button-download').addEventListener('click', function(event) {
169 | event.preventDefault();
170 | download('cppinsights.txt', cppEditor.getValue());
171 | });
172 |
173 | function download(filename, text) {
174 | var pom = document.createElement('a');
175 | pom.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
176 | pom.setAttribute('download', filename);
177 | if (document.createEvent) {
178 | var event = document.createEvent('MouseEvents');
179 | event.initEvent('click', true, true);
180 | pom.dispatchEvent(event);
181 | } else {
182 | pom.click();
183 | }
184 | }
185 |
186 | function toggleButton(divId) { // eslint-disable-line no-unused-vars
187 | var element = document.getElementById(divId).style;
188 |
189 | if ('none' == element.display) {
190 | element.display = 'initial';
191 |
192 | } else {
193 | element.display = 'none';
194 |
195 | }
196 |
197 | setLocalStorageItem(divId, element.display);
198 | }
199 |
200 | function setElementDisplay(divId, value) {
201 | var element = document.getElementById(divId).style;
202 |
203 | element.display = value;
204 | }
205 |
206 | setElementDisplay('banner', getLocalStorageItem('banner', 'initial'));
207 | showHideConsole(getLocalStorageItem('stderr-div', 'initial'));
208 |
209 | /* -- resizing columns and rows -- */
210 |
211 | function changeGridConsoleRowHeight(newHeight) {
212 | var allm = document.getElementById('allmain');
213 | var navHeight = document.getElementById('nav').clientHeight + 'px';
214 |
215 | allm.style.gridTemplateRows = navHeight + ' ' + 'auto' + ' 10px ' + newHeight;
216 | }
217 |
218 | var dragging = false;
219 | var draggingMode = '';
220 | var consoleClosed = false;
221 |
222 | function showHideConsole(show) {
223 | var elem = document.getElementById('stderr-div');
224 | var err = document.getElementById('errstd');
225 | var oldHeight = err.clientHeight;
226 |
227 | var allm = document.getElementById('allmain');
228 |
229 | var element = elem.style;
230 | var minimized = document.getElementById('console-btn');
231 |
232 | if (show) {
233 | element.display = 'initial';
234 |
235 | allm.style.removeProperty('grid-template-rows');
236 |
237 | minimized.classList.remove('minimized');
238 | // refresh codemirror, otherwise the editor contains the old value
239 | stdErrEditor.refresh();
240 |
241 | } else {
242 | var height = elem.clientHeight;
243 |
244 | element.display = 'none';
245 | var errStyleHeight = 'calc(' + oldHeight + 'px - ' + height + 'px)';
246 | changeGridConsoleRowHeight(errStyleHeight);
247 |
248 | minimized.classList.add('minimized');
249 | }
250 |
251 | consoleClosed = (element.display == 'none');
252 | }
253 |
254 | function toggleConsole() { // eslint-disable-line no-unused-vars
255 | var element = document.getElementById('stderr-div').style;
256 |
257 | showHideConsole('none' == element.display);
258 |
259 | setLocalStorageItem('stderr-div', !consoleClosed);
260 | }
261 |
262 | function dragstart(e, mode) {
263 | e.preventDefault();
264 | dragging = true;
265 | draggingMode = mode;
266 | }
267 |
268 | function dragmove(e) {
269 | if (dragging) {
270 | var percentage = 0;
271 | var mainPercentage = 0;
272 |
273 | if ('v' == draggingMode) {
274 | percentage = (e.pageX / window.innerWidth) * 100;
275 | if (percentage > 5 && percentage < 98) {
276 | mainPercentage = 100 - percentage;
277 | var allm = document.getElementById('allmain');
278 |
279 | allm.style.gridTemplateColumns = 'calc(' + percentage + '% - 5px) 10px calc(' + mainPercentage + '% - 5px)';
280 | }
281 | } else if ('h' == draggingMode) {
282 | if (consoleClosed) {
283 | return;
284 | }
285 |
286 | percentage = (e.pageY / window.innerHeight) * 100;
287 |
288 | if (percentage > 5 && percentage < 94) {
289 | mainPercentage = 100 - percentage;
290 | changeGridConsoleRowHeight(mainPercentage + '%');
291 | }
292 | }
293 |
294 | }
295 | }
296 |
297 | function dragend() {
298 | dragging = false;
299 | }
300 |
301 | if (window.addEventListener) {
302 | document.getElementById('vdragbar').addEventListener('mousedown', function(e) {
303 | dragstart(e, 'v');
304 | });
305 | document.getElementById('vdragbar').addEventListener('touchstart', function(e) {
306 | dragstart(e, 'v');
307 | });
308 | document.getElementById('hdragbar').addEventListener('mousedown', function(e) {
309 | dragstart(e, 'h');
310 | });
311 | document.getElementById('hdragbar').addEventListener('touchstart', function(e) {
312 | dragstart(e, 'h');
313 | });
314 | window.addEventListener('mousemove', function(e) {
315 | dragmove(e);
316 | });
317 | window.addEventListener('touchmove', function(e) {
318 | dragmove(e);
319 | });
320 | window.addEventListener('mouseup', dragend);
321 | window.addEventListener('touchend', dragend);
322 | }
323 |
324 | /* -- resizing columns and rows -- */
325 |
326 | function getInsightsOptions() {
327 | return $('#insightsOptions').multipleSelect('getSelects', 'value');
328 | }
329 |
330 | function getCppStd() {
331 | var filtered = getInsightsOptions().filter(function(value, index, arr) { // eslint-disable-line no-unused-vars
332 | return value.startsWith('cpp');
333 | });
334 |
335 | return filtered[0];
336 | }
337 |
338 | function getUseLibStdCpp() {
339 | var filtered = getInsightsOptions().filter(function(value, index, arr) { // eslint-disable-line no-unused-vars
340 | return value.startsWith('use-libcpp');
341 | });
342 |
343 | if (0 == filtered.length) {
344 | return null;
345 | }
346 |
347 | return filtered[0];
348 | }
349 |
350 | function OnRunKeyDown(e) {
351 | if (!((e.keyCode == 10 || e.keyCode == 13) && e.ctrlKey)) return;
352 | Transform();
353 | }
354 |
355 | function OnRunClicked(e) {
356 | e.preventDefault();
357 | Transform();
358 | cppEditor.focus();
359 | }
360 |
361 | function OnWaitForResultKeyDown(e) {
362 | if (!((e.keyCode == 10 || e.keyCode == 13) && e.ctrlKey)) return;
363 | stdErrEditor.setValue('A request is already in the air...');
364 | }
365 |
366 | function OnWaitForResultRunClicked(e) {
367 | e.preventDefault();
368 | stdErrEditor.setValue('A request is already in the air...');
369 | }
370 |
371 | function RunListenersSetup(addKeyDown, removeRunBtn, addRunBtn) {
372 | window.onkeyup = addKeyDown;
373 |
374 | var runButton = document.querySelector('.button-run');
375 | if (runButton) {
376 | runButton.title = 'Run C++ Insights (' + (mac ? 'Cmd-Return' : 'Ctrl-Enter') + ')';
377 | runButton.removeEventListener('click', removeRunBtn);
378 | runButton.addEventListener('click', addRunBtn);
379 | }
380 | cppEditor.focus();
381 | }
382 |
383 | function SetRunListeners() {
384 | RunListenersSetup(OnRunKeyDown, OnWaitForResultRunClicked, OnRunClicked);
385 | }
386 |
387 | // set them initially
388 | SetRunListeners();
389 |
390 | function SetupRequestShortLinkListener() {
391 | var requestShortLinkButton = document.querySelector('#rqslbtn');
392 | if (requestShortLinkButton) {
393 | requestShortLinkButton.title = 'Request short link';
394 | requestShortLinkButton.addEventListener('click', RequestShortLink);
395 | }
396 | }
397 |
398 | SetupRequestShortLinkListener();
399 |
400 | function RemoveRequestShortLinkListener() {
401 | var requestShortLinkButton = document.querySelector('#rqslbtn');
402 | if (requestShortLinkButton) {
403 | requestShortLinkButton.removeEventListener('click', RequestShortLink);
404 | }
405 | }
406 |
407 | function SetWaitForResultListeners() {
408 | RunListenersSetup(OnWaitForResultKeyDown, OnRunClicked, OnWaitForResultRunClicked);
409 | }
410 |
411 | function CopyClick() { // eslint-disable-line no-unused-vars
412 | var textToCopy = document.getElementById('lnkurl');
413 |
414 | textToCopy.select();
415 |
416 | document.execCommand('copy');
417 | }
418 |
419 | function RequestShortLinkClick() { // eslint-disable-line no-unused-vars
420 | RequestShortLink();
421 | }
422 |
423 | // at least FireFox has a problem with just btoa with UTF-8 characters
424 | function b64UTFEncode(str) {
425 | return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, v) {
426 | return String.fromCharCode(parseInt(v, 16));
427 | }));
428 | }
429 |
430 | function updateLinkToCompilerExplorer() {
431 | var cppstdparam = '-std=' + getCppStd().replace('cpp', 'c++');
432 |
433 | var libCpp = getUseLibStdCpp();
434 | if (null != libCpp) {
435 | cppstdparam += ' -stdlib=libc++';
436 | }
437 |
438 | var clientstate = {
439 | sessions: [{
440 | id: 1,
441 | language: 'c++',
442 | source: cppEditor.getValue(),
443 | compilers: [{
444 | id: 'clang_trunk',
445 | options: cppstdparam
446 | }]
447 | }]
448 | };
449 |
450 | var link = location.protocol + '//compiler-explorer.com/clientstate/' + b64UTFEncode(JSON.stringify(clientstate));
451 | var ceButton = document.getElementById('button-ce');
452 | ceButton.href = link;
453 | }
454 |
455 | document.querySelector('#button-ce').addEventListener('mousedown', function() {
456 | updateLinkToCompilerExplorer();
457 | });
458 |
459 | // From: https://github.com/mattgodbolt/compiler-explorer/pull/1823/files
460 | function asciiEncodeJsonText(json) {
461 | return json.replace(/[\u007F-\uFFFF]/g, function(chr) {
462 | // json unicode escapes must always be 4 characters long, so pad with leading zeros
463 | return '\\u' + ('0000' + chr.charCodeAt(0).toString(16)).substr(-4);
464 | });
465 | }
466 |
467 | function updateLinkToQuickBench() {
468 | var quickBenchState = {
469 | text: cppEditor.getValue()
470 | };
471 |
472 | var link = 'http:' /*location.protocol*/ + '//quick-bench.com/#' + b64UTFEncode(asciiEncodeJsonText(JSON.stringify(
473 | quickBenchState)));
474 | var qbButton = document.getElementById('button-qb');
475 | qbButton.href = link;
476 | }
477 |
478 | document.querySelector('#button-qb').addEventListener('mousedown', function() {
479 | updateLinkToQuickBench();
480 | });
481 |
482 | function getLongLinkBase() {
483 | var cppStd = getCppStd();
484 | var insightsOptions = getInsightsOptions();
485 | var text = 'lnk?code=' + b64UTFEncode(cppEditor.getValue()) + '&insightsOptions=' +
486 | insightsOptions + '&std=' + cppStd + '&rev=' + DEFAULT_REV;
487 |
488 | return text;
489 | }
490 |
491 | document.querySelector('.button-create-link').addEventListener('click', function(event) {
492 | event.preventDefault();
493 | event.stopPropagation();
494 | var text = buildURL('/' + getLongLinkBase());
495 |
496 | var lnkElement = document.getElementById('lnkurl');
497 | lnkElement.value = text;
498 |
499 | var lnkDescElement = document.getElementById('lnkdesc');
500 | lnkDescElement.value = '';
501 |
502 | var element = document.getElementById('copyDropdown');
503 | element.classList.toggle('show');
504 | });
505 |
506 | document.querySelector('.button-more').addEventListener('click', function(event) {
507 | event.preventDefault();
508 | event.stopPropagation();
509 |
510 | var element = document.getElementById('moreDropdown');
511 | element.classList.toggle('show');
512 | });
513 |
514 | window.onclick = function(event) {
515 | if (!event.target.matches('.dropbtn') && !event.target.matches('.cpybtn') && !event.target.matches('#lnkurl') &&
516 | !event.target.matches('#lnkdesc') && !event.target.matches('#rqslbtn')) {
517 |
518 | var dropdowns = document.getElementsByClassName('copyDownDownContent');
519 | var i;
520 | for (i = 0; i < dropdowns.length; i++) {
521 | var openDropdown = dropdowns[i];
522 | if (openDropdown.classList.contains('show')) {
523 | openDropdown.classList.remove('show');
524 | }
525 | }
526 | }
527 | };
528 |
529 | // without trailing '/'
530 | function getURLBase() {
531 | return location.protocol + '//' + location.hostname + (location.port ? ':' + location.port : '');
532 | }
533 |
534 | function buildURL(url) {
535 | return getURLBase() + url;
536 | }
537 |
538 | // Send a transformation request to the server
539 | function Transform() { // eslint-disable-line no-unused-vars
540 |
541 | var request = new XMLHttpRequest();
542 |
543 | setLocalStorageItem('code', cppEditor.getValue());
544 | setLocalStorageItem('insightsOptions', getInsightsOptions());
545 |
546 | request.onreadystatechange = function() {
547 | if (this.readyState == 4 && this.status == 200) {
548 | var response = JSON.parse(this.responseText);
549 | cppOutEditor.setValue(response.stdout);
550 | stdErrEditor.setValue(response.stderr);
551 | SetRunListeners();
552 | } else if (this.readyState == 4 && this.status != 200) {
553 | stdErrEditor.setValue('Sorry, your request failed');
554 | SetRunListeners();
555 | }
556 | };
557 |
558 | stdErrEditor.setValue('Waiting for response...');
559 |
560 | var url = buildURL('/api/v1/transform');
561 |
562 | request.open('POST', url, true);
563 | request.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
564 |
565 | var data = {};
566 |
567 | data.insightsOptions = getInsightsOptions();
568 | data.code = cppEditor.getValue();
569 |
570 | SetWaitForResultListeners();
571 | request.send(JSON.stringify(data));
572 | }
573 |
574 | // Send a short link request to the server
575 | function RequestShortLink() { // eslint-disable-line no-unused-vars
576 |
577 | var request = new XMLHttpRequest();
578 |
579 | request.onreadystatechange = function() {
580 | var linkField = document.getElementById('lnkurl');
581 |
582 | if (this.readyState == 4 && this.status == 200) {
583 | var response = JSON.parse(this.responseText);
584 |
585 | linkField.value = buildURL(response.shortlink);
586 | } else if (this.readyState == 4 && this.status != 200) {
587 | linkField.value = 'Sorry, your request failed';
588 | }
589 |
590 | SetupRequestShortLinkListener();
591 | };
592 |
593 | var linkField = document.getElementById('lnkurl');
594 | var linkDescField = document.getElementById('lnkdesc');
595 | var longLink = getLongLinkBase();
596 |
597 | // trim spaces and empty newlines from begin and end?
598 |
599 | linkField.value = 'Please wait...';
600 |
601 | var url = buildURL('/api/v1/getshortlink');
602 |
603 | request.open('POST', url, true);
604 | request.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
605 |
606 | var data = {};
607 |
608 | data.longurl = longLink;
609 | data.code = b64UTFEncode(cppEditor.getValue());
610 | data.desc = b64UTFEncode(linkDescField.value);
611 | data.rev = DEFAULT_REV;
612 | data.std = getCppStd();
613 | data.options = getInsightsOptions();
614 |
615 | RemoveRequestShortLinkListener();
616 |
617 | request.send(JSON.stringify(data));
618 | }
619 |
--------------------------------------------------------------------------------
/app/static/js/settings.js:
--------------------------------------------------------------------------------
1 | /* C++ Insights Web, copyright (c) by Andreas Fertig
2 | Distributed under an MIT license. See /LICENSE */
3 |
4 | /* global getLocalStorageItem, setLocalStorageItem, storageAllowed, createComplianceCookie */
5 |
6 | function toggleButton(divId, show) { // eslint-disable-line no-unused-vars
7 | var value = 'initial';
8 |
9 | if (!show) {
10 | value = 'none';
11 |
12 | }
13 |
14 | setLocalStorageItem(divId, value);
15 | }
16 |
17 | function applyTheme(dark) {
18 | if (dark) {
19 | document.body.setAttribute('data-theme', 'dark');
20 | } else {
21 | document.body.removeAttribute('data-theme');
22 | }
23 | }
24 |
25 | function toggleTheme(dark) {
26 | applyTheme(dark);
27 |
28 | setLocalStorageItem('dark-theme', dark);
29 | }
30 |
31 | function adjustTheme() {
32 | applyTheme(getLocalStorageItem('dark-theme', false));
33 | }
34 |
35 | var settingsConfiguration = [
36 | // name, get-function, set-function, requires cookies
37 | ['Accept cookies', storageAllowed, createComplianceCookie, false],
38 | ['Show community events', function() {
39 | return 'initial' === getLocalStorageItem('banner', 'initial');
40 | }, function(b) {
41 | toggleButton('banner', b);
42 | }, true],
43 | ['Minimize console', function() {
44 | return getLocalStorageItem('stderr-div', false);
45 | }, function(b) {
46 | setLocalStorageItem('stderr-div', !b);
47 | }, true],
48 | ['Use dark theme', function() {
49 | return getLocalStorageItem('dark-theme', false);
50 | }, toggleTheme, true],
51 | ];
52 |
53 | // settings
54 | function SettingsHandler() {
55 | var settingsList = document.getElementById('settings');
56 | if (null == settingsList) {
57 | // settings page not loaded
58 | return;
59 | }
60 |
61 | while (settingsList.firstChild) {
62 | settingsList.removeChild(settingsList.firstChild);
63 | }
64 |
65 | function createSetting(item, index) {
66 | var li = document.createElement('li');
67 |
68 | var input = document.createElement('input');
69 | input.setAttribute('type', 'checkbox');
70 | var label = document.createElement('label');
71 | var text = document.createTextNode(item[0]);
72 | label.appendChild(text);
73 |
74 | input.checked = item[1]();
75 |
76 | // disable cookie related items, if cookies are not allowed
77 | if ((item[3] == true) && !storageAllowed()) {
78 | input.disabled = true;
79 | }
80 |
81 | li.appendChild(input);
82 | li.appendChild(label);
83 |
84 | input.addEventListener('change', (event) => {
85 | item[2](event.target.checked);
86 |
87 | if (0 == index) { // assuming that cookies are at pos 0
88 | // reload the entire list to prevent changes to cookie related items
89 | SettingsHandler();
90 | }
91 | });
92 |
93 | settingsList.appendChild(li);
94 | }
95 |
96 | settingsConfiguration.forEach(createSetting);
97 |
98 | }
99 |
100 | SettingsHandler();
101 |
102 | // set to dark if enabled
103 | adjustTheme();
104 |
--------------------------------------------------------------------------------
/app/static/ms/Readme.md:
--------------------------------------------------------------------------------
1 | This is a third-party component and not covered by the license of the C++ Insights project.
2 |
--------------------------------------------------------------------------------
/app/static/privacy-policy.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | C++ Insights - Privacy Policy
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | Home
35 | About
36 |
37 | Policies
38 |
39 | Examples
40 |
41 |
42 |
43 |
44 |
45 |
46 |
50 |
51 |
52 |
53 |
54 |
55 | C++ Insights Privacy Policy
56 |
57 |
58 | Your Data
59 |
60 | Your data always remains in your control.
61 |
62 | The source code you typed in the editor window is send to the C++ Insights server. At the server your source
63 | code is temporarily stored just to compile it, after that the source code on the server is deleted and the
64 | result
65 | is sent back to your browser.
66 |
67 | Web logs
68 |
69 | C++ Insights keeps web logs to be able to track down issues with the website. These logs are kept for a short
70 | period, after which they are permanently deleted.
71 |
72 | Cookies & Local Storage
73 |
74 | C++ Insights uses small pieces of information stored on your computer: Cookies and Local Storage. These help
75 | to
76 | restore your source code the next time you visit C++ Insights. It also keeps the C++ Standard you have
77 | selected.
78 | This information is stored on your computer. Only during the translation it is temporarily transferred to the
79 | C++
80 | Insights server.
81 | They are only used with the user's permission. See the Cookie Policy for
82 | more
83 | information.
84 |
85 | Short Links
86 |
87 | A user can decide to create a short link using the C++ Insights web-interface. The code as well as a time
88 | stamp
89 | and all compiler/insights options are stored in a database together with the short link id. You have no
90 | guarantees, that the links will be kept forever.
91 |
92 | C++ Insights and the GDPR
93 |
94 | Name and Address of the controller
95 | The Controller for the purposes of the General Data Protection Regulation (GDPR), other data protection laws
96 | applicable in member states of the European Union and other provisions related to data protection is:
97 |
98 | Andreas Fertig, andy at cppinsights.io
99 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/app/static/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow:
3 |
--------------------------------------------------------------------------------
/app/static/settings.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | C++ Insights - Settings
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | Home
22 | About
23 |
24 | Policies
25 |
26 | Examples
27 | Settings
28 |
29 |
30 |
31 |
32 |
33 |
34 |
38 |
39 |
40 |
41 |
42 |
43 | C++ Insights - Local Settings
44 |
45 |
47 |
48 |
49 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/app/static/sitemap.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | https://cppinsights.io
4 |
5 |
6 | https://cppinsights.io/about.html
7 |
8 |
9 | https://cppinsights.io/cookie-policy.html
10 |
11 |
12 | https://cppinsights.io/privacy-policy.html
13 |
14 |
15 | https://cppinsights.io/examples.html
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/templates/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | C++ Insights - 404
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Home
23 | About
24 |
25 | Policies
26 |
27 | Examples
28 | Settings
29 |
30 |
31 |
32 |
33 |
34 |
35 |
39 |
40 |
41 |
42 |
43 |
44 | 404 - Page Not Found
45 |
46 | Sorry, the content your are looking for is not there.
47 |
48 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/app/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | C++ Insights{{ desc }}
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
63 |
67 |
68 |
69 | Request Short Link
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 | {% for value in selectedInsightsOptions %}
85 |
86 | {% if value.label %}
87 |
88 |
89 | {% elif value.single %}
90 |
91 | {{ value.name }}
92 |
93 | {% else %}
94 | {{ value.name }}
95 |
96 | {% endif %}
97 | {% endfor %}
98 |
99 |
100 |
101 | Default
102 | 15
103 | 18
104 | 20
105 | 22
106 | 26
107 |
108 |
109 |
110 |
111 |
More
112 |
113 |
114 |
115 |
116 |
124 |
132 |
140 |
149 |
158 |
167 |
176 |
185 |
194 |
195 |
196 |
197 |
198 |
199 |
202 |
203 |
204 |
205 |
206 |
210 |
211 |
212 |
213 |
214 |
215 |
Source:
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
Insight:
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
Console:
237 |
238 |
239 |
240 |
241 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
--------------------------------------------------------------------------------
/app/templates/version.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | C++ Insights - Version Information
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Home
23 | About
24 |
25 | Policies
26 |
27 | Examples
28 | Settings
29 |
30 |
31 |
32 |
33 |
34 |
35 |
39 |
40 |
41 |
42 |
43 |
44 | C++ Insights Version Information
45 |
46 | {{ version|safe }}
47 |
48 |
49 | CodeMirror:
50 |
51 |
55 |
56 |
57 |
58 |
59 |
60 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/deploy_rsa.enc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andreasfertig/cppinsights-web/13b1b4886e5037313c9a8957332aead088c27795/deploy_rsa.enc
--------------------------------------------------------------------------------
/insights.wsgi:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | import sys
3 | import logging
4 | logging.basicConfig(stream=sys.stderr)
5 | sys.path.insert(0,"/home/insights/public_html/insights")
6 |
7 | from insights import app as application
8 |
--------------------------------------------------------------------------------
/local.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 | #
4 | # C++ Insights Web, copyright (c) by Andreas Fertig
5 | # Distributed under an MIT license. See /LICENSE
6 | #------------------------------------------------------------------------------
7 |
8 | import app
9 | #------------------------------------------------------------------------------
10 |
11 | if __name__ == "__main__":
12 | a = app.getApp()
13 | # set the parameters for running it without sudo
14 | a.config['USE_DOCKER'] = True
15 | a.config['USE_SUDO'] = False
16 |
17 | # run the app
18 | a.run(host='0.0.0.0')
19 | #------------------------------------------------------------------------------
20 |
21 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cppinsights-web",
3 | "version": "1.0.0",
4 | "description": "C++ Insights - Web Front-End",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "nyc mocha",
8 | "report-coverage": "nyc --reporter=lcov npm test"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git+https://github.com/andreasfertig/cppinsights-web.git"
13 | },
14 | "author": "Andreas Fertig",
15 | "license": "MIT",
16 | "bugs": {
17 | "url": "https://github.com/andreasfertig/cppinsights-web/issues"
18 | },
19 | "homepage": "https://github.com/andreasfertig/cppinsights-web#readme",
20 | "dependencies": {
21 | "grunt": "1.6.1",
22 | "grunt-cli": "^1.4.3",
23 | "js-beautify": "^1.8.8",
24 | "uglify-es": "github:mishoo/UglifyJS2#harmony"
25 | },
26 | "devDependencies": {
27 | "async": "^3.2.5",
28 | "eslint": "^8.56.0",
29 | "grunt-contrib-copy": "^1.0.0",
30 | "grunt-contrib-cssmin": "^5.0.0",
31 | "grunt-contrib-htmlmin": "^3.1.0",
32 | "grunt-contrib-imagemin": "^4.0.0",
33 | "grunt-contrib-uglify": "^5.0.1",
34 | "grunt-contrib-uglify-es": "^3.3.0",
35 | "grunt-eslint": "^24.3.0",
36 | "grunt-jsbeautifier": "^0.2.13",
37 | "grunt-shell": "^4.0.0",
38 | "grunt-string-replace": "^1.3.1",
39 | "grunt-svgmin": "^7.0.0",
40 | "jsdom": "24.0.0",
41 | "jsdom-global": "3.0.2",
42 | "mocha": "^10.3.0",
43 | "nyc": "^15.1.0"
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/pics/window-maximize.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/pics/window-minimize.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | flask
2 | pysqlite3-binary
3 |
--------------------------------------------------------------------------------
/requirements_gh.txt:
--------------------------------------------------------------------------------
1 | flask
2 | pysqlite3
3 | coverage
4 | testfixtures
5 | mock
6 |
--------------------------------------------------------------------------------
/test/cookie.test.js:
--------------------------------------------------------------------------------
1 | require('jsdom-global')()
2 |
3 | var app = require('../app/static/js/cookie.js');
4 |
5 | // insert an additional cookie at front to test parsing multiple cookies
6 | function createCookie(name, value) {
7 | var days = 365;
8 | var date = new Date();
9 | date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
10 | var expires = '; expires=' + date.toGMTString();
11 |
12 | document.cookie = name + '=' + value + expires + '; path=/';
13 | }
14 |
15 | var assert = require('assert');
16 | describe('Cookie', function() {
17 | createCookie('dummy', 'nothing');
18 | // banner gets inserted during window load
19 | app.onLoad();
20 |
21 | it('innerHTML contains cookie-law node', function() {
22 | assert.notEqual(document.getElementById('cookie-law'), null);
23 | });
24 |
25 | it('storageAllowed returns false at startup', function() {
26 | assert.equal(app.storageAllowed(), false);
27 | });
28 |
29 | it('User declines cookie -> cookieAccept(false)', function() {
30 | // user clicks decline
31 | app.cookieAccept(false);
32 |
33 | assert.equal(app.storageAllowed(), false);
34 | assert.equal(document.getElementById('cookie-law'), null);
35 | });
36 |
37 | it('User accepts cookie -> cookieAccept(true)', function() {
38 | // simulate reload
39 | this.jsdom = require('jsdom-global')()
40 | app.onLoad();
41 |
42 | // user clicks accept
43 | app.cookieAccept(true);
44 |
45 | assert.equal(app.storageAllowed(), true);
46 | assert.equal(document.getElementById('cookie-law'), null);
47 | });
48 |
49 | it('ensure no cookie banner is shown', function() {
50 | // simulate reload
51 | var cookie = document.cookie; // keep existing cookies
52 | this.jsdom = require('jsdom-global')() // reset the DOM
53 | document.cookie = cookie; // restore existing cookies
54 | app.onLoad(); // reload
55 |
56 | assert.equal(document.getElementById('cookie-law'), null);
57 | });
58 |
59 | });
60 |
--------------------------------------------------------------------------------