├── .babelrc
├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── fonts
├── Droid_Sans_Mono
│ ├── DroidSansMono.ttf
│ └── LICENSE.txt
├── FiraCode
│ ├── FiraCode-Regular.otf
│ └── LICENSE
└── Josefin_Sans
│ ├── JosefinSans-Bold.ttf
│ ├── JosefinSans-BoldItalic.ttf
│ ├── JosefinSans-Italic.ttf
│ ├── JosefinSans-Light.ttf
│ ├── JosefinSans-LightItalic.ttf
│ ├── JosefinSans-Regular.ttf
│ ├── JosefinSans-SemiBold.ttf
│ ├── JosefinSans-SemiBoldItalic.ttf
│ ├── JosefinSans-Thin.ttf
│ ├── JosefinSans-ThinItalic.ttf
│ └── OFL.txt
├── gulpfile.babel.js
├── icons
├── mancy.icns
├── mancy.ico
└── mancy.png
├── images
├── auto-suggestion-2.png
├── auto-suggestion.png
├── await-progress.png
├── await-resolved.png
├── babel.png
├── base64-viz.png
├── buffer-viz.png
├── chart-area-spline.png
├── chart-area.png
├── chart-bar.png
├── chart-flip.png
├── chart-line.png
├── chart-pie.png
├── chart-rotate.png
├── chart-spline.png
├── color-viz.png
├── console-dups.png
├── console-window-2.png
├── console-window.png
├── dark-theme-2.png
├── dark-theme.png
├── date-visualization.png
├── font-preference.png
├── global-env-dark.png
├── global-env-light.png
├── grid-dark.png
├── grid-light.png
├── grid-transpose.png
├── html-viz.png
├── integer-viz.png
├── light-theme-2.png
├── light-theme.png
├── live-highlight.png
├── node-modules-preference.png
├── object-output.png
├── preference-dark.png
├── preference-light.png
├── promise-pending.png
├── promise-resolved.png
├── regex-viz.png
├── source-2.png
├── source-track.png
├── source.png
├── store-as-global-after.png
├── store-as-global-before.png
├── timeout-in-progress.png
├── timeout.png
├── transpiled-view.png
├── underscore.png
├── warn-quit.png
└── zoom-preference.png
├── index.html
├── logos
├── cljs.png
├── coffee.png
├── js.png
├── ls.png
└── ts.png
├── menus
├── context-menu.json
├── darwin.json
├── linux.json
└── win32.json
├── package.json
├── src
├── Startup.js
├── actions
│ ├── ReplActions.js
│ ├── ReplActiveInputActions.js
│ ├── ReplConsoleActions.js
│ ├── ReplPreferencesActions.js
│ ├── ReplStatusBarActions.js
│ └── ReplSuggestionActions.js
├── app.js
├── common
│ ├── ReplCommon.js
│ ├── ReplConsoleHook.js
│ ├── ReplContext.js
│ ├── ReplDOM.js
│ ├── ReplDOMEvents.js
│ ├── ReplFonts.js
│ ├── ReplInput.js
│ ├── ReplOutput.js
│ ├── ReplStreamHook.js
│ ├── ReplType.js
│ └── ReplUndo.js
├── components
│ ├── Repl.js
│ ├── ReplActiveIcon.js
│ ├── ReplActiveInput.js
│ ├── ReplConsole.js
│ ├── ReplConsoleEnvironmentWatcher.js
│ ├── ReplConsoleMessageFilters.js
│ ├── ReplEntries.js
│ ├── ReplEntry.js
│ ├── ReplEntryIcon.js
│ ├── ReplEntryMessage.js
│ ├── ReplEntryOutputError.js
│ ├── ReplEntryStatus.js
│ ├── ReplFontFamily.js
│ ├── ReplNotebook.js
│ ├── ReplOutputArray.js
│ ├── ReplOutputBuffer.js
│ ├── ReplOutputBufferExplorer.js
│ ├── ReplOutputChartViewer.js
│ ├── ReplOutputColor.js
│ ├── ReplOutputCrypto.js
│ ├── ReplOutputDate.js
│ ├── ReplOutputFunction.js
│ ├── ReplOutputGridViewer.js
│ ├── ReplOutputHTML.js
│ ├── ReplOutputInteger.js
│ ├── ReplOutputObject.js
│ ├── ReplOutputPromise.js
│ ├── ReplOutputRegex.js
│ ├── ReplOutputString.js
│ ├── ReplOutputTranspile.js
│ ├── ReplOutputURL.js
│ ├── ReplPageZoom.js
│ ├── ReplPreferences.js
│ ├── ReplPrompt.js
│ ├── ReplSourceFile.js
│ ├── ReplStatusBar.js
│ ├── ReplSuggestions.js
│ ├── __mocks__
│ │ ├── clipboard.js
│ │ └── shell.js
│ ├── __tests__
│ │ ├── ReplActiveIcon-test.js
│ │ ├── ReplConsole-test.js
│ │ ├── ReplConsoleMessageFilters-test.js
│ │ ├── ReplEntries-test.js
│ │ ├── ReplEntry-test.js
│ │ ├── ReplEntryIcon-test.js
│ │ ├── ReplEntryMessage-test.js
│ │ ├── ReplEntryOutputError-test.js
│ │ ├── ReplEntryStatus-test.js
│ │ ├── ReplOutputArray-test.js
│ │ ├── ReplOutputFunction-test.js
│ │ ├── ReplOutputObject-test.js
│ │ ├── ReplPrompt-test.js
│ │ └── ReplStatusBar-test.js
│ └── clojurescript
│ │ ├── ReplOutputCljsDoc.js
│ │ ├── ReplOutputCljsDocs.js
│ │ ├── ReplOutputCljsFun.js
│ │ ├── ReplOutputCljsMeta.js
│ │ ├── ReplOutputCljsSeq.js
│ │ ├── ReplOutputCljsSource.js
│ │ ├── ReplOutputCljsVal.js
│ │ ├── ReplOutputCljsVar.js
│ │ └── ReplOutputCljsWrapper.js
├── constants
│ └── ReplConstants.js
├── languages
│ ├── ReplClojureScript.js
│ ├── ReplLangWrapper.js
│ ├── ReplLanguages.js
│ ├── ReplLiveScript.js
│ ├── ReplTypeScript.js
│ └── typescript
│ │ └── node.d.ts
├── main
│ ├── MenuManager.js
│ └── index.js
└── stores
│ ├── ReplActiveInputStore.js
│ ├── ReplConsoleStore.js
│ ├── ReplPreferencesStore.js
│ ├── ReplStatusBarStore.js
│ ├── ReplStore.js
│ └── ReplSuggestionStore.js
└── stylesheets
├── clojurescript
├── repl-output-cljs-docs.scss
├── repl-output-cljs-meta.scss
├── repl-output-cljs-source.scss
├── repl-output-cljs-val.scss
├── repl-output-cljs-var.scss
└── repl-output-cljs-wrapper.scss
├── configs.scss
├── dark-theme.scss
├── highlight.scss
├── light-theme.scss
├── repl-common.scss
├── repl-console-environment-watcher.scss
├── repl-console-message.scss
├── repl-container-left.scss
├── repl-container-right.scss
├── repl-editor.scss
├── repl-entries.scss
├── repl-entry-message.scss
├── repl-entry-status.scss
├── repl-output-array.scss
├── repl-output-buffer-explorer.scss
├── repl-output-chart-viewer.scss
├── repl-output-color.scss
├── repl-output-crypto.scss
├── repl-output-grid-viewer.scss
├── repl-output-html.scss
├── repl-output-integer.scss
├── repl-output-object.scss
├── repl-output-regex.scss
├── repl-output-string.scss
├── repl-output-url.scss
├── repl-output.scss
├── repl-preferences.scss
├── repl-prompt.scss
├── repl-source-file.scss
├── repl-status-bar.scss
├── repl-suggestions.scss
├── repl.scss
└── themes.scss
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "react", "stage-0"],
3 | "plugins": ["add-module-exports", [
4 | "transform-runtime", {
5 | "polyfill": false,
6 | "regenerator": true
7 | }]
8 | ]
9 | }
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | bower_components
3 | dist
4 | tmp
5 | devtools
6 | coverage
7 | build
8 | .DS_Store
9 | *.log
10 | .*
11 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "4.1"
4 | - "4.0"
5 | - "0.12"
6 | - "0.11"
7 | - "0.10"
8 | - "iojs"
9 | #before_script:
10 | # - npm install -g gulp
11 | #script: gulp
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Prince John Wesley (princejohnwesley@gmail.com)
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 | # Mancy
2 |
3 | A cross platform NodeJS REPL application based on electron and react frameworks.
4 |
5 | [](https://gitter.im/princejwesley/Mancy)
6 | [](https://github.com/princejwesley/Mancy/issues/126)
7 |
8 | ## [Language Support](http://mancy-re.pl)
9 |
10 | - [JavaScript](https://en.wikipedia.org/wiki/JavaScript)
11 | - [CoffeeScript](http://coffeescript.org/)
12 | - [TypeScript](http://www.typescriptlang.org/)
13 | - [LiveScript](http://livescript.net/)
14 | - [ClojureScript](http://clojure.org/about/clojurescript)
15 |
16 | ## [Features](http://mancy-re.pl)
17 |
18 | - Syntax Highlighting
19 | - Dark and light themes
20 | - Load and save session history
21 | - Separate console window for async stdout/stderr logs
22 | - Notification for async console logs
23 | - console output filter support
24 | - Traversable output with fold/unfold options
25 | - Support for adding directory to node path
26 | - Expand/Collapse/reload command options
27 | - History traversal support
28 | - Multiple window
29 | - Multiline prompt support with shift + enter
30 | - Auto suggestion
31 | - Tab completion
32 | - Code format support
33 | - Support to toggle REPL mode
34 | - Preferences for theme and REPL mode
35 |
36 | #### [Version II :star2:](https://github.com/princejwesley/Mancy/wiki/Version-II)
37 |
38 | - Download npm modules on demand
39 | - Babel support
40 | - await with auto async wrapper
41 | - Data visualization support
42 | - Integer representation (bin/oct/dec/hex and signed/unsigned)
43 | - Regular expression live editor
44 | - Buffer explorer
45 | - HTML view
46 | - CSS color view
47 | - base64 detection
48 | - Basic chart representation of data
49 | - Image detection / display
50 | - Download buffers support
51 | - Support to break long lasting commands
52 | - Preference window
53 | - Promise output tracking
54 | - Source file open support for node modules(`.source name`)
55 | - No special meaning for `_`
56 | - Syntax highlight as we type
57 |
58 | For more detailed documentation, [read here](https://github.com/princejwesley/Mancy/wiki/Version-II)
59 |
60 | ## [Wiki](http://github.com/princejwesley/Mancy/wiki)
61 | [wiki](http://github.com/princejwesley/Mancy/wiki) page has documentation for new features.
62 |
63 | ## [Screenshots](http://mancy-re.pl)
64 |
65 | #### light theme
66 |
67 |
68 | #### dark theme
69 |
70 |
71 | #### console section
72 |
73 |
74 | #### auto suggestion
75 |
76 |
77 | #### function source
78 |
79 |
80 |
81 | # Installation
82 | - `npm install -g mancy` (or)
83 | - Download from [latest release](https://github.com/princejwesley/Mancy/releases/latest) (or)
84 | - [Clone](https://github.com/princejwesley/Mancy/) and run `npm install` & `npm run package`. Executable file will be created inside `./dist/` directory.
85 | - To build native modules, make sure `node` >=4.x and `npm` >= 3.x installed.
86 | - Refer [node-gyp](https://github.com/nodejs/node-gyp#installation) for native module build failure.
87 |
88 | ## Developers
89 |
90 | [Fork](https://github.com/princejwesley/Mancy/) and run `npm run debug` or `gulp debug` to debug this application.
91 |
92 | ## Notification
93 | Subscribe [this thread](https://github.com/princejwesley/Mancy/issues/126) for new features and release notification.
94 |
95 | ## Ideas & Suggestions
96 | Find consolidated ideas and suggestions [here](https://github.com/princejwesley/Mancy/wiki/Ideas-&-Suggestions).
97 |
98 | ## License
99 | [MIT License](https://github.com/princejwesley/Mancy/blob/master/LICENSE)
100 |
--------------------------------------------------------------------------------
/fonts/Droid_Sans_Mono/DroidSansMono.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/fonts/Droid_Sans_Mono/DroidSansMono.ttf
--------------------------------------------------------------------------------
/fonts/FiraCode/FiraCode-Regular.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/fonts/FiraCode/FiraCode-Regular.otf
--------------------------------------------------------------------------------
/fonts/Josefin_Sans/JosefinSans-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/fonts/Josefin_Sans/JosefinSans-Bold.ttf
--------------------------------------------------------------------------------
/fonts/Josefin_Sans/JosefinSans-BoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/fonts/Josefin_Sans/JosefinSans-BoldItalic.ttf
--------------------------------------------------------------------------------
/fonts/Josefin_Sans/JosefinSans-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/fonts/Josefin_Sans/JosefinSans-Italic.ttf
--------------------------------------------------------------------------------
/fonts/Josefin_Sans/JosefinSans-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/fonts/Josefin_Sans/JosefinSans-Light.ttf
--------------------------------------------------------------------------------
/fonts/Josefin_Sans/JosefinSans-LightItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/fonts/Josefin_Sans/JosefinSans-LightItalic.ttf
--------------------------------------------------------------------------------
/fonts/Josefin_Sans/JosefinSans-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/fonts/Josefin_Sans/JosefinSans-Regular.ttf
--------------------------------------------------------------------------------
/fonts/Josefin_Sans/JosefinSans-SemiBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/fonts/Josefin_Sans/JosefinSans-SemiBold.ttf
--------------------------------------------------------------------------------
/fonts/Josefin_Sans/JosefinSans-SemiBoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/fonts/Josefin_Sans/JosefinSans-SemiBoldItalic.ttf
--------------------------------------------------------------------------------
/fonts/Josefin_Sans/JosefinSans-Thin.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/fonts/Josefin_Sans/JosefinSans-Thin.ttf
--------------------------------------------------------------------------------
/fonts/Josefin_Sans/JosefinSans-ThinItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/fonts/Josefin_Sans/JosefinSans-ThinItalic.ttf
--------------------------------------------------------------------------------
/fonts/Josefin_Sans/OFL.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2010, Santiago Orozco (hi@typemade.mx)
2 | This Font Software is licensed under the SIL Open Font License, Version 1.1.
3 | This license is copied below, and is also available with a FAQ at:
4 | http://scripts.sil.org/OFL
5 |
6 |
7 | -----------------------------------------------------------
8 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
9 | -----------------------------------------------------------
10 |
11 | PREAMBLE
12 | The goals of the Open Font License (OFL) are to stimulate worldwide
13 | development of collaborative font projects, to support the font creation
14 | efforts of academic and linguistic communities, and to provide a free and
15 | open framework in which fonts may be shared and improved in partnership
16 | with others.
17 |
18 | The OFL allows the licensed fonts to be used, studied, modified and
19 | redistributed freely as long as they are not sold by themselves. The
20 | fonts, including any derivative works, can be bundled, embedded,
21 | redistributed and/or sold with any software provided that any reserved
22 | names are not used by derivative works. The fonts and derivatives,
23 | however, cannot be released under any other type of license. The
24 | requirement for fonts to remain under this license does not apply
25 | to any document created using the fonts or their derivatives.
26 |
27 | DEFINITIONS
28 | "Font Software" refers to the set of files released by the Copyright
29 | Holder(s) under this license and clearly marked as such. This may
30 | include source files, build scripts and documentation.
31 |
32 | "Reserved Font Name" refers to any names specified as such after the
33 | copyright statement(s).
34 |
35 | "Original Version" refers to the collection of Font Software components as
36 | distributed by the Copyright Holder(s).
37 |
38 | "Modified Version" refers to any derivative made by adding to, deleting,
39 | or substituting -- in part or in whole -- any of the components of the
40 | Original Version, by changing formats or by porting the Font Software to a
41 | new environment.
42 |
43 | "Author" refers to any designer, engineer, programmer, technical
44 | writer or other person who contributed to the Font Software.
45 |
46 | PERMISSION & CONDITIONS
47 | Permission is hereby granted, free of charge, to any person obtaining
48 | a copy of the Font Software, to use, study, copy, merge, embed, modify,
49 | redistribute, and sell modified and unmodified copies of the Font
50 | Software, subject to the following conditions:
51 |
52 | 1) Neither the Font Software nor any of its individual components,
53 | in Original or Modified Versions, may be sold by itself.
54 |
55 | 2) Original or Modified Versions of the Font Software may be bundled,
56 | redistributed and/or sold with any software, provided that each copy
57 | contains the above copyright notice and this license. These can be
58 | included either as stand-alone text files, human-readable headers or
59 | in the appropriate machine-readable metadata fields within text or
60 | binary files as long as those fields can be easily viewed by the user.
61 |
62 | 3) No Modified Version of the Font Software may use the Reserved Font
63 | Name(s) unless explicit written permission is granted by the corresponding
64 | Copyright Holder. This restriction only applies to the primary font name as
65 | presented to the users.
66 |
67 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
68 | Software shall not be used to promote, endorse or advertise any
69 | Modified Version, except to acknowledge the contribution(s) of the
70 | Copyright Holder(s) and the Author(s) or with their explicit written
71 | permission.
72 |
73 | 5) The Font Software, modified or unmodified, in part or in whole,
74 | must be distributed entirely under this license, and must not be
75 | distributed under any other license. The requirement for fonts to
76 | remain under this license does not apply to any document created
77 | using the Font Software.
78 |
79 | TERMINATION
80 | This license becomes null and void if any of the above conditions are
81 | not met.
82 |
83 | DISCLAIMER
84 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
85 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
86 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
87 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
88 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
89 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
90 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
91 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
92 | OTHER DEALINGS IN THE FONT SOFTWARE.
93 |
--------------------------------------------------------------------------------
/icons/mancy.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/icons/mancy.icns
--------------------------------------------------------------------------------
/icons/mancy.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/icons/mancy.ico
--------------------------------------------------------------------------------
/icons/mancy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/icons/mancy.png
--------------------------------------------------------------------------------
/images/auto-suggestion-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/auto-suggestion-2.png
--------------------------------------------------------------------------------
/images/auto-suggestion.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/auto-suggestion.png
--------------------------------------------------------------------------------
/images/await-progress.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/await-progress.png
--------------------------------------------------------------------------------
/images/await-resolved.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/await-resolved.png
--------------------------------------------------------------------------------
/images/babel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/babel.png
--------------------------------------------------------------------------------
/images/base64-viz.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/base64-viz.png
--------------------------------------------------------------------------------
/images/buffer-viz.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/buffer-viz.png
--------------------------------------------------------------------------------
/images/chart-area-spline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/chart-area-spline.png
--------------------------------------------------------------------------------
/images/chart-area.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/chart-area.png
--------------------------------------------------------------------------------
/images/chart-bar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/chart-bar.png
--------------------------------------------------------------------------------
/images/chart-flip.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/chart-flip.png
--------------------------------------------------------------------------------
/images/chart-line.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/chart-line.png
--------------------------------------------------------------------------------
/images/chart-pie.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/chart-pie.png
--------------------------------------------------------------------------------
/images/chart-rotate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/chart-rotate.png
--------------------------------------------------------------------------------
/images/chart-spline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/chart-spline.png
--------------------------------------------------------------------------------
/images/color-viz.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/color-viz.png
--------------------------------------------------------------------------------
/images/console-dups.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/console-dups.png
--------------------------------------------------------------------------------
/images/console-window-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/console-window-2.png
--------------------------------------------------------------------------------
/images/console-window.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/console-window.png
--------------------------------------------------------------------------------
/images/dark-theme-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/dark-theme-2.png
--------------------------------------------------------------------------------
/images/dark-theme.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/dark-theme.png
--------------------------------------------------------------------------------
/images/date-visualization.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/date-visualization.png
--------------------------------------------------------------------------------
/images/font-preference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/font-preference.png
--------------------------------------------------------------------------------
/images/global-env-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/global-env-dark.png
--------------------------------------------------------------------------------
/images/global-env-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/global-env-light.png
--------------------------------------------------------------------------------
/images/grid-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/grid-dark.png
--------------------------------------------------------------------------------
/images/grid-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/grid-light.png
--------------------------------------------------------------------------------
/images/grid-transpose.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/grid-transpose.png
--------------------------------------------------------------------------------
/images/html-viz.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/html-viz.png
--------------------------------------------------------------------------------
/images/integer-viz.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/integer-viz.png
--------------------------------------------------------------------------------
/images/light-theme-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/light-theme-2.png
--------------------------------------------------------------------------------
/images/light-theme.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/light-theme.png
--------------------------------------------------------------------------------
/images/live-highlight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/live-highlight.png
--------------------------------------------------------------------------------
/images/node-modules-preference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/node-modules-preference.png
--------------------------------------------------------------------------------
/images/object-output.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/object-output.png
--------------------------------------------------------------------------------
/images/preference-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/preference-dark.png
--------------------------------------------------------------------------------
/images/preference-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/preference-light.png
--------------------------------------------------------------------------------
/images/promise-pending.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/promise-pending.png
--------------------------------------------------------------------------------
/images/promise-resolved.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/promise-resolved.png
--------------------------------------------------------------------------------
/images/regex-viz.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/regex-viz.png
--------------------------------------------------------------------------------
/images/source-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/source-2.png
--------------------------------------------------------------------------------
/images/source-track.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/source-track.png
--------------------------------------------------------------------------------
/images/source.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/source.png
--------------------------------------------------------------------------------
/images/store-as-global-after.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/store-as-global-after.png
--------------------------------------------------------------------------------
/images/store-as-global-before.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/store-as-global-before.png
--------------------------------------------------------------------------------
/images/timeout-in-progress.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/timeout-in-progress.png
--------------------------------------------------------------------------------
/images/timeout.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/timeout.png
--------------------------------------------------------------------------------
/images/transpiled-view.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/transpiled-view.png
--------------------------------------------------------------------------------
/images/underscore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/underscore.png
--------------------------------------------------------------------------------
/images/warn-quit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/warn-quit.png
--------------------------------------------------------------------------------
/images/zoom-preference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/images/zoom-preference.png
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/logos/cljs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/logos/cljs.png
--------------------------------------------------------------------------------
/logos/coffee.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/logos/coffee.png
--------------------------------------------------------------------------------
/logos/js.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/logos/js.png
--------------------------------------------------------------------------------
/logos/ls.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/logos/ls.png
--------------------------------------------------------------------------------
/logos/ts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/princejwesley/Mancy/ff61e6e1603b5c94658084024a47cd4505ba6373/logos/ts.png
--------------------------------------------------------------------------------
/menus/context-menu.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "label": "Cut",
4 | "accelerator": "CmdOrCtrl+X",
5 | "role": "cut"
6 | },
7 | {
8 | "label": "Copy",
9 | "accelerator": "CmdOrCtrl+C",
10 | "role": "copy"
11 | },
12 | {
13 | "label": "Paste",
14 | "accelerator": "CmdOrCtrl+V",
15 | "role": "paste"
16 | },
17 | {
18 | "label": "Select All",
19 | "accelerator": "CmdOrCtrl+A",
20 | "role": "selectall"
21 | },
22 | {
23 | "type": "separator"
24 | }
25 | ]
26 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mancy",
3 | "private": true,
4 | "version": "3.2.0",
5 | "description": "A GUI REPL for Javascript & more…",
6 | "main": "main/index.js",
7 | "scripts": {
8 | "preinstall": "npm prune",
9 | "postinstall": "electron-rebuild && gulp clean && gulp copy",
10 | "test": "jest",
11 | "cov": "jest --coverage",
12 | "start": "gulp start",
13 | "debug": "gulp debug",
14 | "package": "npm dedupe && gulp package",
15 | "package-all": "npm dedupe && gulp packageAll",
16 | "release": "gulp release",
17 | "watch": "gulp watch",
18 | "build": "gulp build"
19 | },
20 | "jest": {
21 | "scriptPreprocessor": "../node_modules/babel-jest",
22 | "unmockedModulePathPatterns": [
23 | "./node_modules/react",
24 | "./node_modules/reflux",
25 | "./node_modules/lodash"
26 | ],
27 | "verbose": true,
28 | "rootDir": "./src"
29 | },
30 | "keywords": [
31 | "REPL",
32 | "JavaScript",
33 | "CoffeeScript",
34 | "TypeScript",
35 | "LiveScript",
36 | "ClojureScript"
37 | ],
38 | "author": "Prince John Wesley ",
39 | "license": "MIT",
40 | "devDependencies": {
41 | "babel": "^6.3.13",
42 | "babel-jest": "^6.0.1",
43 | "babel-polyfill": "^6.3.14",
44 | "del": "^2.0.2",
45 | "devtron": "^1.0.0",
46 | "electron-packager": "^8.0.0",
47 | "electron": "^1.4.15",
48 | "electron-rebuild": "^1.5.7",
49 | "gulp": "^3.9.0",
50 | "gulp-babel": "^6.1.1",
51 | "gulp-cached": "^1.1.0",
52 | "gulp-cli": "^0.3.0",
53 | "gulp-concat": "^2.6.0",
54 | "gulp-env": "^0.2.0",
55 | "gulp-livereload": "^3.8.0",
56 | "gulp-load-plugins": "^0.10.0",
57 | "gulp-react": "^3.0.1",
58 | "gulp-sass": "^2.0.4",
59 | "gulp-util": "^3.0.6",
60 | "jest-cli": "^0.5.8",
61 | "node-sass": "^3.3.2",
62 | "react-tools": "0.13.3",
63 | "run-sequence": "^1.1.2",
64 | "semver": "^5.0.3"
65 | },
66 | "dependencies": {
67 | "babel-core": "^6.7.0",
68 | "babel-runtime": "^6.9.1",
69 | "babel-plugin-add-module-exports": "^0.1.1",
70 | "babel-plugin-transform-runtime": "^6.3.13",
71 | "babel-preset-es2015": "^6.3.13",
72 | "babel-preset-react": "^6.3.13",
73 | "babel-preset-stage-0": "^6.3.13",
74 | "c3": "https://github.com/princejwesley/c3.git",
75 | "cljs-mancy": "^1.0.0",
76 | "codemirror": "^5.13.0",
77 | "coffee-script": "https://github.com/princejwesley/coffeescript.git",
78 | "font-awesome": "^4.5.0",
79 | "font-manager": "^0.2.2",
80 | "github": "^0.2.4",
81 | "is-css-color": "^1.0.0",
82 | "livescript": "^1.4.0",
83 | "lodash": "^3.10.1",
84 | "md5": "^2.0.0",
85 | "parinfer": "^1.7.0",
86 | "react": "^0.13.3",
87 | "reflux": "^0.2.12",
88 | "typescript": "^1.8.2",
89 | "yargs": "^3.32.0"
90 | },
91 | "settings": {
92 | "disable-font-manager": true
93 | },
94 | "repository": {
95 | "type": "git",
96 | "url": "https://github.com/princejwesley/Mancy.git"
97 | },
98 | "bugs": {
99 | "url": "https://github.com/princejwesley/Mancy/issues/new"
100 | },
101 | "homepage": "https://github.com/princejwesley/Mancy"
102 | }
103 |
--------------------------------------------------------------------------------
/src/Startup.js:
--------------------------------------------------------------------------------
1 |
2 | require('./app');
3 |
--------------------------------------------------------------------------------
/src/actions/ReplActions.js:
--------------------------------------------------------------------------------
1 | import Reflux from 'reflux';
2 |
3 | const ReplActions = Reflux.createActions([
4 | "addEntry",
5 | "updateEntry",
6 | "removeEntry",
7 | "reloadPrompt",
8 | "reloadPromptByIndex",
9 | "toggleCommandEntryView",
10 | "toggleEntryView",
11 | "setREPLMode",
12 | "setEditorMode",
13 | "overrideLastOutput",
14 | "bindObjectToContext",
15 | ]);
16 | export default ReplActions;
17 |
--------------------------------------------------------------------------------
/src/actions/ReplActiveInputActions.js:
--------------------------------------------------------------------------------
1 | import Reflux from 'reflux';
2 |
3 | const ReplActiveInputActions = Reflux.createActions([
4 | "tabCompleteSuggestion",
5 | "resetTabCompleteSuggestion",
6 | "fillTabCompleteSuggestion",
7 | "breakPrompt",
8 | "formatCode",
9 | "playCommands",
10 | "updateSuggestionDelay",
11 | "performAutoComplete",
12 | "setTheme",
13 | "setEditorOption",
14 | "undo",
15 | "redo",
16 | "selectAll",
17 | "focus",
18 | "setMode"
19 | ]);
20 | export default ReplActiveInputActions;
21 |
--------------------------------------------------------------------------------
/src/actions/ReplConsoleActions.js:
--------------------------------------------------------------------------------
1 | import Reflux from 'reflux';
2 |
3 | const ReplConsoleActions = Reflux.createActions([
4 | "addEntry",
5 | "clear"
6 | ]);
7 | export default ReplConsoleActions;
8 |
--------------------------------------------------------------------------------
/src/actions/ReplPreferencesActions.js:
--------------------------------------------------------------------------------
1 | import Reflux from 'reflux';
2 |
3 | const ReplPreferencesActions = Reflux.createActions([
4 | "togglePreferences",
5 | "openPreferences",
6 | "closePreferences",
7 | "setTheme",
8 | "setREPLMode",
9 | "changeFontFamily",
10 | "changePageZoomFactor",
11 | ]);
12 | export default ReplPreferencesActions;
13 |
--------------------------------------------------------------------------------
/src/actions/ReplStatusBarActions.js:
--------------------------------------------------------------------------------
1 | import Reflux from 'reflux';
2 |
3 | const ReplStatusBarActions = Reflux.createActions([
4 | "updateRunCommand",
5 | "newRelease",
6 | "updateLanguage",
7 | "updateMode",
8 | "refresh",
9 | "cursorActivity"
10 | ]);
11 | export default ReplStatusBarActions;
12 |
--------------------------------------------------------------------------------
/src/actions/ReplSuggestionActions.js:
--------------------------------------------------------------------------------
1 | import Reflux from 'reflux';
2 |
3 | const ReplSuggestionActions = Reflux.createActions([
4 | "addSuggestion",
5 | "removeSuggestion"
6 | ]);
7 | export default ReplSuggestionActions;
8 |
--------------------------------------------------------------------------------
/src/common/ReplConsoleHook.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash';
2 | import EventEmitter from 'events';
3 |
4 | let console = require('console');
5 | class ReplConsoleHook extends EventEmitter {
6 | constructor() {
7 | super();
8 |
9 | _.each(['error', 'warn', 'info', 'log', 'debug'], (fun) => {
10 | this[fun] = (...rest) => {
11 | this.emit('console', {type: fun, data: rest});
12 | };
13 | console[fun] = this[fun];
14 | });
15 | }
16 | }
17 | let hook = new ReplConsoleHook();
18 | export default hook;
19 |
--------------------------------------------------------------------------------
/src/common/ReplDOMEvents.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash';
2 | import ReplConstants from '../constants/ReplConstants';
3 |
4 | const navigation = {
5 | 'keyLeft': 37,
6 | 'keyup': 38,
7 | 'keyRight': 39,
8 | 'keydown': 40,
9 | };
10 |
11 | const events = {
12 | 'blurEvent': 'blur',
13 | 'keydownEvent': 'keydown',
14 | 'keyupEvent': 'keyup',
15 | };
16 |
17 | const keyNameBindings = {
18 | 'tab': 9,
19 | 'enter': 13,
20 | 'escape': 27,
21 | 'space': 32,
22 | 'quote': 222,
23 | 'backTick': 192,
24 | 'backSpace': 8,
25 | };
26 |
27 | let combined = _.extend({}, keyNameBindings, navigation);
28 |
29 | let reducer = (input, attr) => {
30 | return _.chain(input)
31 | .keys()
32 | .map((key) => [key, (e) => e[attr] === input[key]])
33 | .reduce((result, [key, fun]) => {
34 | result['is' + _.capitalize(key)] = fun;
35 | return result;
36 | }, {})
37 | .value();
38 | };
39 |
40 |
41 | let ReplDOMEvents = _.extend({}, reducer(combined, 'which'), reducer(events, 'type'));
42 |
43 | ReplDOMEvents.isNavigation = (() => {
44 | let values = _.values(navigation);
45 | return (e) => values.indexOf(e.which) !== -1;
46 | })();
47 |
48 | ReplDOMEvents.autoFillPairCharacters = {
49 | '"' : '"',
50 | "'" : "'",
51 | '`' : '`',
52 | '{' : '}',
53 | '[' : ']',
54 | '(' : ')',
55 | '}' : '{',
56 | ']' : '[',
57 | ')' : '('
58 | };
59 |
60 | ReplDOMEvents.autoCloseKeyIdentifiers = {
61 | '"' : "U+0022",
62 | "'" : "U+0027",
63 | "[" : "U+005B",
64 | "]" : "U+005D",
65 | "{" : "U+007B",
66 | "}" : "U+007D",
67 | "(" : "U+0028",
68 | ")" : "U+0029",
69 | "`" : "U+0060",
70 | };
71 |
72 | ReplDOMEvents.duplicate = (e) => new e.constructor(e.type, e);
73 |
74 | // keyCodes for alphabets A-Z
75 | const A = 'A'.charCodeAt(0);
76 | _.each('ABCDEFGHIJKLMNOPQRSTUVWXYZ', (c, pos) => {
77 | ReplDOMEvents[c] = A + pos;
78 | });
79 |
80 | ReplDOMEvents.zero = '0'.charCodeAt(0); //48
81 | ReplDOMEvents.nine = ReplDOMEvents.zero + 9; //'9'.charCodeAt(0);
82 | ReplDOMEvents.isNumber = (e) => e.which >= ReplDOMEvents.zero && e.which <= ReplDOMEvents.nine;
83 |
84 | export default ReplDOMEvents;
85 |
--------------------------------------------------------------------------------
/src/common/ReplFonts.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash';
2 |
3 | const weights = {
4 | 100: 'Thin',
5 | 200: 'Ultra Light',
6 | 300: 'Light',
7 | 400: 'Normal',
8 | 500: 'Medium',
9 | 600: 'Semi Bold',
10 | 700: 'Bold',
11 | 800: 'Ultra Bold',
12 | 900: 'Heavy',
13 | };
14 |
15 | const widths = {
16 | 1: 'Ultra Condensed',
17 | 2: 'Extra Condensed',
18 | 3: 'Condensed',
19 | 4: 'Semi Condensed',
20 | 5: 'Normal',
21 | 6: 'Semi Expanded',
22 | 7: 'Expanded',
23 | 8: 'Extra Expanded',
24 | 9: 'Ultra Expanded',
25 | };
26 |
27 | const systemFonts = (() => {
28 | try {
29 | const settings = require('./../package.json').settings;
30 | const locals = [
31 | { family: 'Droid Sans Mono' },
32 | { family: 'FiraCode' },
33 | { family: 'Josefin Sans' }
34 | ];
35 | return _.chain(settings['disable-font-manager'] ? locals : require('font-manager').getAvailableFontsSync())
36 | .tap((fonts) => {
37 | locals.forEach(f => fonts.push(f));
38 | })
39 | .sortBy("family")
40 | .map((f) => f.family)
41 | .uniq(true)
42 | .value();
43 | } catch(e) {
44 | // disable font preferences
45 | return [];
46 | }
47 | })();
48 |
49 | const getSystemFonts = () => systemFonts;
50 | const setFontFamily = (family = 'monospace', defaults = 'sans-serif') => document.body.style.fontFamily = `${family}, ${defaults}`;
51 |
52 | export default { getSystemFonts, setFontFamily };
53 |
--------------------------------------------------------------------------------
/src/common/ReplInput.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash';
2 | import ReplConstants from '../constants/ReplConstants';
3 | import ReplCommon from './ReplCommon';
4 | import ReplOutput from '../common/ReplOutput';
5 | let babel = require('babel-core');
6 |
7 | const functionMatcher = /^\s*\bfunction\s+(..*?)\(/;
8 | const awaitMatcher = /^(?:\s*(?:(?:let|var|const)\s)?\s*([^=]+)=\s*|^\s*)(await\s[\s\S]*)/;
9 | const sourceMatcher = /^\s*(\.source)\s+([^\s]+)\s*$/;
10 | const importMatcher = /\bimport\s+(?:(?:{(.+?)})|(.+?))\s+from\s+(['"])(.+?)\3/g;
11 | const bindAsMatcher = /(.*)\s+as\s+(.*)/;
12 | const asDefaultMatcher = /(?:\*|default)\s+as/;
13 | const USE_STRICT_LENGTH = "'user strict;'".length;
14 |
15 |
16 | let funTransformer = (source, find, replace) =>
17 | `var ${replace} = function ${replace}(${source.substring(find.length)}`;
18 | let asyncWrapper = (code, binder) => {
19 | // Babel is not happy, ensure that async is not top level
20 | // let assign = binder ? `root.${binder} = result;` : '';
21 | // return `(async function() { let result = (${code}); ${assign} return result; }())`;
22 | let assign = binder ? `root.${binder} = ` : '';
23 | return `(function(){ async function _wrap() { return ${assign}${code} } return _wrap();})()`;
24 | };
25 |
26 | let importToRequire = (prefix, bindings, asBinding, __, modname) => {
27 | if(asBinding) {
28 | return `var ${asBinding.replace(asDefaultMatcher, '')} = (require('${modname}').default || require('${modname}'));`;
29 | }
30 | let result = Array.join((bindings).trim()
31 | .split(',')
32 | .map(m => {
33 | const asM = m.trim();
34 | const asBound = asM.match(bindAsMatcher);
35 | const [x, y] = asBound ? [asBound[1], asBound[2]] : [asM, asM];
36 | const attr = x === 'default' || x === '*' ? '' : `.${x}`;
37 | return `root.${y} = (require('${modname}').default || require('${modname}'))${attr};\n`
38 | }), '');
39 | return `${result}; void 0;`;
40 | };
41 |
42 |
43 | let cook = (plain) => {
44 | let tplain = plain.trim();
45 | let source = tplain.match(sourceMatcher);
46 | if(source) {
47 | let mod = source[2];
48 | return {
49 | local: true,
50 | output: ReplOutput.source(mod),
51 | input: `.source ${mod} `
52 | }
53 | }
54 |
55 | let output = plain, force = false;
56 |
57 | if(global.Mancy.session.lang === 'js') {
58 | let funMatch = output.match(functionMatcher);
59 | if(funMatch) {
60 | output = `${funTransformer(output, funMatch[0], funMatch[1])}`;
61 | }
62 | if(global.Mancy.preferences.asyncWrap) {
63 | // bare await
64 | let match = output.match(awaitMatcher);
65 | if(match) {
66 | output = `${asyncWrapper(match[2], match[1])}`;
67 | force = true;
68 | }
69 | }
70 | if(!force && plain.indexOf('import') !== -1) {
71 | output = plain.replace(importMatcher, importToRequire);
72 | }
73 | }
74 |
75 | return {
76 | force,
77 | local: false,
78 | output: global.Mancy.session.babel && global.Mancy.session.lang === 'js' ? babelTransfrom(output) : output
79 | };
80 | };
81 |
82 | let babelTransfrom = (plain) => {
83 | try {
84 | let matchCommonJS = (opt) => opt === 'transform-es2015-modules-commonjs';
85 | let strict = false;
86 |
87 | if(global.Mancy.session.mode === 'Strict') {
88 | strict = true;
89 | if(_.findIndex(ReplConstants.BABEL_OPTIONS.plugins, matchCommonJS) === -1) {
90 | ReplConstants.BABEL_OPTIONS.plugins.push('transform-es2015-modules-commonjs');
91 | }
92 | } else { _.remove(ReplConstants.BABEL_OPTIONS.plugins, matchCommonJS); }
93 |
94 | let code = babel
95 | .transform(plain, ReplConstants.BABEL_OPTIONS)
96 | .code;
97 |
98 | // transform imports added by babel scripts into require
99 | if(!strict && code.indexOf('import') !== -1) {
100 | code = code.replace(importMatcher, importToRequire);
101 | }
102 |
103 | return strict ? code.substring(USE_STRICT_LENGTH - 1) : code;
104 | } catch(e) {
105 | return e;
106 | }
107 | }
108 |
109 | let ReplInput = {
110 | transform: (plain) => {
111 | return cook(plain);
112 | }
113 | };
114 |
115 | export default ReplInput;
116 |
--------------------------------------------------------------------------------
/src/common/ReplStreamHook.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash';
2 | import EventEmitter from 'events';
3 |
4 | // only stdout and stderr
5 | class ReplStreamHook extends EventEmitter {
6 | constructor() {
7 | super();
8 | _.each([['stdout', process.stdout], ['stderr', process.stderr]], ([name, stream]) => {
9 | stream.write = ((stream) => {
10 | return (chunk, encoding, fd) => {
11 | this.emit(name, { data: chunk, encoding: encoding, fd: fd });
12 | };
13 | })(stream);
14 | });
15 | }
16 | }
17 | export default new ReplStreamHook();
18 |
--------------------------------------------------------------------------------
/src/common/ReplUndo.js:
--------------------------------------------------------------------------------
1 |
2 | class ReplUndoItem {
3 | constructor(ts, action, data) {
4 | this.ts = ts;
5 | this.action = action;
6 | this.data = data;
7 | }
8 | }
9 |
10 | // seconds pulse
11 | export default class ReplUndo {
12 | constructor(context=null, pulse = 1000) {
13 | this.stack = [];
14 | this.pos = -1;
15 | this.pulse = Math.abs(pulse);
16 | this.context = context;
17 | }
18 |
19 | add(data, action) {
20 | let nts = parseInt(Date.now() / this.pulse);
21 | let item = new ReplUndoItem(nts, action, data);
22 | if(this.pos > 0) {
23 | let {ts} = this.stack[this.pos];
24 | if(ts !== nts) {
25 | this.pos++;
26 | this.stack.splice(this.pos);
27 | this.stack.push(item);
28 | } else {
29 | this.stack[this.pos] = item;
30 | }
31 | } else {
32 | this.pos = 0;
33 | this.stack.push(item);
34 | }
35 | }
36 |
37 | undo(data, action) {
38 | if(this.pos >= 0) {
39 | let {action, data} = this.stack[this.pos];
40 | this.pos--;
41 | action.call(this.context, data, ReplUndo.Undo);
42 | }
43 | }
44 |
45 | redo(data, action) {
46 | const item = this.stack[this.pos + 1];
47 | if(item) {
48 | let {action, data} = item;
49 | this.pos++;
50 | action.call(this.context, data, ReplUndo.Redo);
51 | }
52 | }
53 |
54 | reset() {
55 | this.stack = [];
56 | this.pos = -1;
57 | }
58 |
59 | static Undo = Symbol('undo');
60 | static Redo = Symbol('redo');
61 | }
62 |
--------------------------------------------------------------------------------
/src/components/ReplActiveIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default class ReplActiveIcon extends React.Component {
4 | constructor(props) {
5 | super(props);
6 | }
7 | render() {
8 | return (
9 |
10 |
11 |
12 | );
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/components/ReplConsoleEnvironmentWatcher.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReplContext from '../common/ReplContext';
3 | import _ from 'lodash';
4 | import ReplOutput from '../common/ReplOutput';
5 |
6 | export default class ReplConsoleEnvironmentWatcher extends React.Component {
7 | constructor(props) {
8 | super(props);
9 | this.context = ReplContext.getContext();
10 | this.getProperties = this.getProperties.bind(this);
11 | this.getENV = this.getENV.bind(this);
12 | this.toggleFunsView = this.toggleFunsView.bind(this);
13 | this.toggleValuesView = this.toggleValuesView.bind(this);
14 | this.state = {
15 | funView: true,
16 | valueView: true
17 | };
18 | }
19 |
20 | getProperties(names) {
21 | let context = ReplContext.getContext();
22 | return _.map(names, (key) => {
23 | let value = ReplOutput.readProperty(context, key);
24 | let keyClass = Object.prototype.propertyIsEnumerable.call(context, key) ? 'env-key' : 'env-key dull';
25 | return (
26 |
27 | {
28 |
29 | {key.toString()}
30 |
31 | }
32 |
33 | {
34 | value && value._isReactElement
35 | ? {value}
36 | : ReplOutput.transformObject(value)
37 | }
38 |
39 |
40 | )
41 | })
42 | }
43 |
44 | getENV() {
45 | let context = ReplContext.getContext();
46 | let userDefinedNames = _.sortBy(_.difference(Object.getOwnPropertyNames(context), ReplContext.alphaNames));
47 | return _.partition(userDefinedNames, (name) => typeof context[name] === 'function');
48 | }
49 |
50 | toggleValuesView() {
51 | this.setState({
52 | valueView: !this.state.valueView
53 | });
54 | }
55 |
56 | toggleFunsView() {
57 | this.setState({
58 | funView: !this.state.funView
59 | });
60 | }
61 |
62 | render() {
63 | let [funs, vals] = this.getENV();
64 | let valueClass = `repl-console-environment-listing-title fa ${this.state.valueView ? 'fa-minus-square-o': 'fa-plus-square-o'}`;
65 | let funClass = `repl-console-environment-listing-title fa ${this.state.funView ? 'fa-minus-square-o': 'fa-plus-square-o'}`;
66 | return (
67 |
68 |
69 |
70 | Global Environment
71 |
72 |
73 |
74 |
75 | Values
76 |
77 |
78 | {
79 | this.state.valueView
80 | ? vals.length
81 | ?
82 | {
83 | this.getProperties(vals)
84 | }
85 |
86 | :
No values
87 | : null
88 | }
89 |
90 | Functions
91 |
92 |
93 | {
94 | this.state.funView
95 | ? funs.length
96 | ?
97 | {
98 | this.getProperties(funs)
99 | }
100 |
101 | :
No functions
102 | : null
103 | }
104 |
105 |
106 | );
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/src/components/ReplConsoleMessageFilters.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default class ReplConsoleMessageFilters extends React.Component {
4 | constructor(props) {
5 | super(props);
6 |
7 | }
8 |
9 | render() {
10 | return (
11 |
12 |
13 |
14 |
17 |
18 | A
19 |
20 |
21 |
25 |
26 | E
27 |
28 |
29 |
33 |
34 | W
35 |
36 |
37 |
41 |
42 | I
43 |
44 |
45 |
49 |
50 | L
51 |
52 |
53 |
57 |
58 | D
59 |
60 |
61 |
62 |
63 |
64 |
65 | );
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/components/ReplEntries.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 | import ReplEntry from './ReplEntry';
4 |
5 | export default class ReplEntries extends React.Component {
6 | constructor(props) {
7 | super(props);
8 | }
9 | render() {
10 | return (
11 |
12 | {
13 | _.chain(this.props.entries)
14 | .filter(entry => entry.plainCode && entry.plainCode.trim().length)
15 | .map((entry, pos) => {
16 | return ;
17 | })
18 | .value()
19 | }
20 |
21 | );
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/components/ReplEntry.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReplEntryIcon from './ReplEntryIcon';
3 | import ReplEntryMessage from './ReplEntryMessage';
4 | import ReplEntryStatus from './ReplEntryStatus';
5 | import ReplActions from '../actions/ReplActions';
6 | import ReplNotebook from './ReplNotebook';
7 | import _ from 'lodash';
8 |
9 | export default class ReplEntry extends React.Component {
10 | constructor(props) {
11 | super(props);
12 | _.each([
13 | 'onToggle', 'onReload',
14 | 'onCommandCollapse', 'onRemove',
15 | ], (field) => {
16 | this[field] = this[field].bind(this);
17 | });
18 | }
19 | onToggle() {
20 | ReplActions.toggleEntryView(this.props.index);
21 | }
22 | onReload() {
23 | ReplActions.reloadPromptByIndex(this.props.index);
24 | }
25 | onRemove() {
26 | ReplActions.removeEntry(this.props.index, this.props.log);
27 | }
28 | onCommandCollapse() {
29 | ReplActions.toggleCommandEntryView(this.props.index);
30 | }
31 |
32 | renderNotebook() {
33 | return (
34 |
35 |
36 |
37 | );
38 | }
39 |
40 | renderREPL() {
41 | return (
42 |
43 |
45 |
47 |
51 |
52 | );
53 | }
54 |
55 | render() {
56 | return global.Mancy.preferences.editor === 'REPL' ? this.renderREPL() : this.renderNotebook();
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/components/ReplEntryIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default class ReplEntryIcon extends React.Component {
4 | constructor(props) {
5 | super(props);
6 | }
7 | render() {
8 | return (
9 |
10 | {
11 | this.props.collapse
12 | ?
13 | :
14 | }
15 |
16 | );
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/components/ReplEntryMessage.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {EOL} from 'os';
3 | import ReplCommon from '../common/ReplCommon';
4 | import ReplConstants from '../constants/ReplConstants';
5 |
6 | export default class ReplEntryMessage extends React.Component {
7 | constructor(props) {
8 | super(props);
9 | }
10 |
11 | getTimeStr(v, u) {
12 | return v ? `${v}${u}` : null;
13 | }
14 |
15 | showExecutionTime() {
16 | if(!this.props.message.time || !global.Mancy.preferences.executionTime) {
17 | return null;
18 | }
19 |
20 | let [s, n] = this.props.message.time;
21 | let m = parseInt(n / 1e6);
22 | let mi = parseInt((n - m * 1e6) / 1e3);
23 | n = n % 1e3;
24 | let time = [
25 | this.getTimeStr(s, 's'), this.getTimeStr(m, 'ms'),
26 | this.getTimeStr(mi,'µs'), this.getTimeStr(n, 'ns')
27 | ].filter(x => x !== null).join(':');
28 |
29 | let clazz = `fa fa-clock-o execution-time ${s > 10 ? 'red' : (s > 5 ? 'orange' : 'green')}`
30 | return
31 | }
32 |
33 | render() {
34 | let shortEntry;
35 | if(this.props.commandCollapse) {
36 | let lines = this.props.message.plainCode.trim().split(EOL);
37 | if(lines.length > 1 || lines[0].length > ReplConstants.COMMAND_TRUNCATE_LENGTH){
38 | shortEntry = ReplCommon.highlight(lines[0].slice(0, ReplConstants.COMMAND_TRUNCATE_LENGTH));
39 | }
40 | }
41 | return (
42 |
43 |
44 | {
45 | this.props.commandCollapse && shortEntry
46 | ?
48 |
49 | :
51 |
52 | }
53 | { this.props.message.ns ?
{this.props.message.ns} : null }
54 | { this.showExecutionTime() }
55 |
56 | { this.props.collapse ?
57 | null :
58 |
59 | {this.props.message.transpiledOutput}
60 | {this.props.message.formattedOutput}
61 |
62 | }
63 |
64 | );
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/components/ReplEntryOutputError.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 | import ReplSourceFile from './ReplSourceFile';
4 | import ReplContext from '../common/ReplContext';
5 | import ReplCommon from '../common/ReplCommon';
6 |
7 | const STACK_TRACE_PRIMARY_PATTERN = /(?:at\s*)([^(]+)\(?([^:]+):(\d+):(\d+)\)?/;
8 | const STACK_TRACE_SECONDARY_PATTERN = /(?:at\s*)()([^:]+):(\d+):(\d+)/;
9 | export default class ReplEntryOutputError extends React.Component {
10 | constructor(props) {
11 | super(props);
12 | this.state = {
13 | collapse: true
14 | }
15 |
16 | this.onToggleCollapse = this.onToggleCollapse.bind(this);
17 |
18 | this.message = this.highlightMessage(this.props.message);
19 |
20 | if (this.props.syntaxError) {
21 | let {error, caret, file} = this.props.syntaxError;
22 | let caretPosition = caret.indexOf('^');
23 | let [start, mid, end] = [
24 | error.substring(0, caretPosition),
25 | error.substring(caretPosition, caret.length),
26 | error.substring(caret.length)
27 | ];
28 | let errorFile = this.highlightMessage(/mancy-repl:/.test(file) ? '' : file.trim());
29 | this.syntaxError =
30 |
{errorFile}
31 |
32 |
{mid}
33 |
34 |
{this.message}
35 |
36 | this.stacktrace = [];
37 | } else {
38 | this.stacktrace = this.highlightException(this.props.trace);
39 | }
40 | }
41 |
42 | onToggleCollapse() {
43 | this.setState({
44 | collapse: !this.state.collapse
45 | });
46 | }
47 |
48 | highlightMessage(msg) {
49 | let output = msg;
50 | let filler = (match, p1, p2) => {
51 | if(p1 && p2) {
52 | output =
53 |
54 | {p1} :{p2}
55 |
56 | }
57 | };
58 | msg.replace(/^([^:]+):(.*)$/, filler);
59 | return output;
60 | }
61 |
62 | highlightException(stack) {
63 | // revisit: top two stacks are ours ?
64 | // stack = stack.slice(2);
65 | let output = [];
66 | let filler = (match, p1, p2, p3, p4) => {
67 | let openBrace = '', closeBrace = '';
68 | if(p1.trim().length) {
69 | openBrace = '(';
70 | closeBrace = ')';
71 | }
72 | let context = ReplContext.getContext();
73 | let location = ReplCommon.getModuleSourcePath(p2, context.module.paths);
74 | if(location) { p2 = }
75 |
76 | output.push(
77 |
78 | at
79 | {p1}
80 | {openBrace}
81 | {p2} :
82 | {p3} :
83 | {p4}
84 | {closeBrace}
85 |
86 | );
87 | return '';
88 | };
89 |
90 | _.each(stack, (s) => {
91 | s.replace(s.indexOf('(') !== -1 ? STACK_TRACE_PRIMARY_PATTERN : STACK_TRACE_SECONDARY_PATTERN, filler);
92 | });
93 | return output;
94 | }
95 |
96 | render() {
97 | return (
98 |
99 | {
100 | !this.stacktrace.length
101 | ?
102 | {this.syntaxError}
103 |
104 | : this.state.collapse
105 | ?
106 |
107 | {this.message}
108 |
109 | :
110 |
111 | {this.message}
112 |
113 | {this.stacktrace}
114 |
115 |
116 | }
117 |
118 | );
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/src/components/ReplEntryStatus.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default class ReplEntryStatus extends React.Component {
4 | constructor(props) {
5 | super(props);
6 | }
7 | render() {
8 | return (
9 |
10 | {
11 | this.props.message.status
12 | ? null
13 | :
15 | }
16 |
17 | {
18 | this.props.collapse
19 | ?
21 | :
22 | }
23 |
24 |
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/components/ReplFontFamily.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 | import ReplPreferencesActions from '../actions/ReplPreferencesActions';
4 | import RepFonts from '../common/ReplFonts';
5 |
6 | export default class ReplFonts extends React.Component {
7 | constructor(props) {
8 | super(props);
9 | this.onChangeFontFamily = this.onChangeFontFamily.bind(this);
10 | }
11 |
12 | onChangeFontFamily(e) {
13 | ReplPreferencesActions.changeFontFamily(e.target.value);
14 | }
15 |
16 | render() {
17 | let fonts = RepFonts.getSystemFonts();
18 | let font = global.Mancy.preferences.fontFamily;
19 | return (
20 |
21 | {
22 | fonts.length
23 | ?
24 |
25 | Font
26 |
27 |
28 |
29 | {
30 | _.map(fonts, (f) => {
31 | return {f}
32 | })
33 | }
34 |
35 |
36 |
37 | : null
38 | }
39 |
40 | );
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/components/ReplNotebook.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReplPrompt from './ReplPrompt';
3 |
4 | export default class ReplNotebook extends React.Component {
5 | constructor(props) {
6 | super(props);
7 | }
8 |
9 | render() {
10 | let {id, tag, plainCode, cursor, transpiledOutput, formattedOutput} = this.props.message;
11 | return (
12 |
13 | {
14 |
21 | }
22 |
23 | {transpiledOutput}
24 | {formattedOutput}
25 |
26 |
27 | );
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/components/ReplOutputArray.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 | import ReplOutput from '../common/ReplOutput';
4 | import ReplOutputObject from './ReplOutputObject';
5 | import ReplCommon from '../common/ReplCommon';
6 | import ReplActions from '../actions/ReplActions';
7 |
8 | export default class ReplOutputArray extends React.Component {
9 | constructor(props) {
10 | super(props);
11 | this.state = {
12 | collapse: true
13 | }
14 |
15 | this.onToggleCollapse = this.onToggleCollapse.bind(this);
16 | this.getKeysButLength = this.getKeysButLength.bind(this);
17 | this.getArrayRecords = this.getArrayRecords.bind(this);
18 | this.getType = this.getType.bind(this);
19 | this.getPrototype = this.getPrototype.bind(this);
20 | this.bindObjectToContext = this.bindObjectToContext.bind(this);
21 | }
22 |
23 | shouldComponentUpdate(nextProps, nextState) {
24 | return !(_.isEqual(nextState, this.state) && _.isEqual(nextProps, this.props));
25 | }
26 |
27 | onToggleCollapse() {
28 | this.setState({
29 | collapse: !this.state.collapse
30 | });
31 | }
32 |
33 | getType() {
34 | let type = ReplCommon.type(this.props.proto);
35 | return ` ${type !== 'Undefined' ? type : 'Array[0]'} {}`;
36 | }
37 |
38 | getKeysButLength() {
39 | // cljs won't return length property since I enumerate the original container
40 | let keys = Object.getOwnPropertyNames(this.props.array).filter( x => x !== 'length');
41 | return keys.slice(0, keys.length);
42 | }
43 |
44 | getPrototype() {
45 | return this.props.proto ||
46 | (this.props.array.length &&
47 | this.props.array[0] &&
48 | this.props.array[0]._isReactElement &&
49 | this.props.array[0]._isReactElement.props.proto
50 | ) ||
51 | Object.getPrototypeOf(this.props.array);
52 | }
53 |
54 | getArrayRecords() {
55 | let continuation = this.props.label.indexOf(' … ') !== -1;
56 | return (
57 |
58 | {
59 | _.map(this.getKeysButLength(), (key) => {
60 | let value = ReplOutput.readProperty(this.props.array, key);
61 | let idx = parseInt(key, 10);
62 | return (
63 |
64 | {
65 | this.props.noIndex || (value && value._isReactElement)
66 | ? null
67 | :
68 | { this.props.start + idx}
69 | :
70 |
71 | }
72 | {
73 | value && value._isReactElement
74 | ? value
75 | : ReplOutput.transformObject(value)
76 | }
77 |
78 | )
79 | })
80 | }
81 | {
82 | continuation
83 | ? null
84 | :
85 | length: {this.props.length ? this.props.length : this.props.array.length}
86 |
87 | }
88 | {
89 | continuation
90 | ? null
91 | :
92 | __proto__
93 | :
94 |
95 |
96 | }
97 |
98 | );
99 | }
100 |
101 | bindObjectToContext() {
102 | ReplActions.bindObjectToContext(this.props.array, ReplOutput.transformObject(this.props.array));
103 | }
104 |
105 | render() {
106 | return (
107 |
108 | {
109 | this.state.collapse
110 | ?
111 |
112 | {this.props.label}
113 |
114 | :
115 |
116 | {this.props.label}
117 |
118 | {this.getArrayRecords()}
119 |
120 | }
121 |
122 | );
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/src/components/ReplOutputColor.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReplOutputString from './ReplOutputString';
3 | import _ from 'lodash';
4 |
5 | export default class ReplOutputColor extends React.Component {
6 | constructor(props) {
7 | super(props);
8 | }
9 |
10 | shouldComponentUpdate(nextProps, nextState) {
11 | return !_.isEqual(nextProps, this.props);
12 | }
13 |
14 | render() {
15 | let colorCode = { backgroundColor: this.props.str };
16 | return (
17 |
18 |
19 |
20 |
21 | );
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/components/ReplOutputCrypto.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReplCommon from '../common/ReplCommon';
3 | import _ from 'lodash';
4 |
5 | export default class ReplOutputCrypto extends React.Component {
6 | constructor(props) {
7 | super(props);
8 | this.state = {
9 | lock: true
10 | };
11 | this.toggleLock = this.toggleLock.bind(this);
12 | this.encodeId = _.uniqueId('crpto-');
13 | this.decodeId = _.uniqueId('crpto-');
14 | }
15 |
16 | shouldComponentUpdate(nextProps, nextState) {
17 | return !(_.isEqual(nextState, this.state) && _.isEqual(nextProps, this.props));
18 | }
19 |
20 | toggleLock() {
21 | this.setState({
22 | lock: !this.state.lock
23 | });
24 | }
25 | render() {
26 | let data = this.state.lock ? this.props.encode : this.props.decode;
27 | let clazz = `fa ${this.state.lock ? 'fa-lock' : 'fa-unlock'}`;
28 | let cryptoClazz = `repl-output-crypto ${this.state.lock && Buffer.isBuffer(this.props.decode) ? 'extend' : ''}`;
29 | let key = `${this.state.lock ? this.encodeId : this.decodeId}-key`;
30 | return (
31 |
32 | {
33 |
34 | {data}
35 |
36 |
37 | }
38 |
39 | );
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/components/ReplOutputDate.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReplOutputObject from './ReplOutputObject';
3 | import _ from 'lodash';
4 |
5 | export default class ReplOutputDate extends React.Component {
6 | constructor(props) {
7 | super(props);
8 | this.state = {
9 | collapse: true
10 | };
11 | this.onToggleCollapse = this.onToggleCollapse.bind(this);
12 | }
13 |
14 | shouldComponentUpdate(nextProps, nextState) {
15 | return !(_.isEqual(nextState, this.state) && _.isEqual(nextProps, this.props));
16 | }
17 |
18 | onToggleCollapse() {
19 | this.setState({
20 | collapse: !this.state.collapse
21 | });
22 | }
23 |
24 | render() {
25 | return (
26 |
27 | {
28 | this.state.collapse
29 | ?
30 |
31 |
32 | {this.props.date.toString()}
33 |
34 | :
35 |
36 |
37 | {this.props.date.toString()}
38 |
39 | {
40 | this.props.date.__proto__
41 | ?
42 | __proto__
43 | :
44 |
45 |
46 | : null
47 | }
48 |
49 |
50 | }
51 |
52 | );
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/components/ReplOutputGridViewer.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 | import ReplOutput from '../common/ReplOutput';
4 | import ReplCommon from '../common/ReplCommon';
5 |
6 | export default class ReplOutputGridViewer extends React.Component {
7 | constructor(props) {
8 | super(props);
9 | this.state = {
10 | collapse: true,
11 | transpose: false
12 | }
13 |
14 | this.gridViewable = this.props.gridViewable || false;
15 | if(!this.gridViewable) {
16 | try{ this.gridViewable = ReplCommon.candidateForGrid(this.props.grid); }
17 | catch(e) {}
18 | }
19 |
20 | _.each([
21 | 'onToggleCollapse', 'onToggleTranspose', 'renderGrid', 'transposeGridData',
22 | 'gridData', 'getCellString'
23 | ], (field) => {
24 | this[field] = this[field].bind(this);
25 | });
26 | }
27 |
28 | shouldComponentUpdate(nextProps, nextState) {
29 | return this.gridViewable && !(_.isEqual(nextState, this.state) && _.isEqual(nextProps, this.props));
30 | }
31 |
32 | onToggleCollapse() {
33 | this.setState({
34 | collapse: !this.state.collapse
35 | });
36 | }
37 |
38 | onToggleTranspose() {
39 | this.setState({
40 | transpose: !this.state.transpose
41 | });
42 | }
43 |
44 | getCellString(cell) {
45 | return _.isDate(cell) ? cell.toDateString().substring(4) : cell.toString();
46 | }
47 |
48 | transposeGridData() {
49 | let toTranspose = () => {
50 | let gridValues = this.gridData();
51 | let data = _.reduce(gridValues, (o, row) => {
52 | _.each(row, (r, pos) => {
53 | o[pos] || o.push([]);
54 | o[pos].push(r);
55 | });
56 | return o;
57 | }, []);
58 | return (this.transposedGridData = data);
59 | };
60 | return this.transposedGridData || toTranspose();
61 | }
62 |
63 | gridData() {
64 | let grid = this.props.grid;
65 | return this.gridValues || (this.gridValues = _.map(_.keys(grid), (key) => _.values(grid[key])));
66 | }
67 |
68 | renderGrid() {
69 | let grid = this.props.grid;
70 | this.colHeaders = this.colHeaders || _.keys(grid);
71 | this.rowHeaders = this.rowHeaders || _.keys(grid[this.colHeaders[0]]);
72 |
73 | let [rowHeaders, colHeaders] = this.state.transpose
74 | ? [this.colHeaders, this.rowHeaders] : [this.rowHeaders, this.colHeaders];
75 |
76 | let data = this.state.transpose ? this.transposeGridData() : this.gridData();
77 | const clazzMap = {
78 | number: 'cm-number',
79 | boolean: 'cm-atom',
80 | object: 'cm-variable',
81 | string: 'cm-string'
82 | };
83 |
84 | return (
85 |
122 | );
123 | }
124 |
125 | render() {
126 | if(!this.gridViewable) { return null; }
127 | return (
128 |
129 | {
130 | this.state.collapse
131 | ?
132 |
133 | Grid Viewer
134 |
135 | :
136 |
137 | Grid Viewer
138 | {this.renderGrid()}
139 |
140 | }
141 |
142 | );
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/src/components/ReplOutputHTML.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 | import ReplConstants from '../constants/ReplConstants';
4 | import md5 from 'md5';
5 |
6 | export default class ReplOutputHTML extends React.Component {
7 | constructor(props) {
8 | super(props);
9 | this.state = {
10 | html: false
11 | };
12 | this.onToggleHTMLView = this.onToggleHTMLView.bind(this);
13 | this.onLoadIFrame = this.onLoadIFrame.bind(this);
14 | this.id = md5(this.props.body.innerText + `-${Date.now()}`);
15 | }
16 |
17 | shouldComponentUpdate(nextProps, nextState) {
18 | return !(_.isEqual(nextState, this.state) && _.isEqual(nextProps, this.props));
19 | }
20 |
21 | componentDidMount() {
22 | this.element = React.findDOMNode(this);
23 | }
24 |
25 | onToggleHTMLView() {
26 | this.setState({
27 | html: !this.state.html
28 | });
29 | }
30 |
31 | onLoadIFrame() {
32 | let iframe = document.getElementById(this.id);
33 | let doc = iframe.contentDocument;
34 | doc.body = this.props.body;
35 | let styles = window.getComputedStyle(doc.body);
36 | let height = parseInt(styles.height) + parseInt(styles.marginTop) + parseInt(styles.marginBottom);
37 | // fix max height
38 | iframe.height = Math.min(height, ReplConstants.IFRAME_MAX_HEIGHT) + 'px';
39 | doc.body.style.color = (document.body.className.indexOf('dark-theme') !== -1 ? 'whitesmoke' : 'darkslategrey');
40 | }
41 |
42 | render() {
43 | let clazz = `fa fa-html5 ${this.state.html ? 'html' : 'nohtml'}`;
44 | return (
45 |
46 | {this.props.source}
47 |
48 | {
49 | this.state.html
50 | ?
53 | : null
54 | }
55 |
56 | );
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/components/ReplOutputInteger.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 |
4 | const mode = {
5 | 'bin' : 2,
6 | 'oct' : 8,
7 | 'dec' : 10,
8 | 'hex' : 16
9 | };
10 |
11 | export default class ReplOutputInteger extends React.Component {
12 | constructor(props) {
13 | super(props);
14 | this.state = {
15 | mode: 'dec',
16 | type: 'signed',
17 | collapse: 'true'
18 | };
19 |
20 | _.each([
21 | 'setMode', 'toIntString', 'getClazz', 'getTypedClazz', 'onSignedMode', 'onUnsignedMode', 'onToggleCollapse'
22 | ], (field) => {
23 | this[field] = this[field].bind(this);
24 | });
25 |
26 | _.each(_.keys(mode), (m) => {
27 | let n = `on${_.capitalize(m)}Mode`;
28 | this[n] = () => this.setMode(m);
29 | this[n].bind(this);
30 | });
31 | }
32 |
33 | shouldComponentUpdate(nextProps, nextState) {
34 | return !(_.isEqual(nextState, this.state) && _.isEqual(nextProps, this.props));
35 | }
36 |
37 | setMode(mode) {
38 | this.setState({
39 | mode: mode
40 | });
41 | }
42 |
43 | onToggleCollapse() {
44 | this.setState({
45 | collapse: !this.state.collapse,
46 | mode: 'dec',
47 | type: 'signed'
48 | });
49 | }
50 |
51 | onSignedMode() {
52 | this.setState({
53 | type: 'signed'
54 | })
55 | }
56 |
57 | onUnsignedMode() {
58 | this.setState({
59 | type: 'unsigned'
60 | })
61 | }
62 |
63 | toIntString(n) {
64 | let num = this.state.type === 'signed' ? n : (n >>> 0);
65 | return (num).toString(mode[this.state.mode]);
66 | }
67 |
68 | getClazz(m) {
69 | return `mode ${this.state.mode === m ? 'selected' : ''}`;
70 | }
71 |
72 | getTypedClazz(m) {
73 | return `mode ${this.state.type === m ? 'selected' : ''}`;
74 | }
75 |
76 | isOutOfRange() {
77 | return this.props.int > -1 && this.props.int < 2;
78 | }
79 |
80 | hide() {
81 | return this.state.collapse || this.isOutOfRange();
82 | }
83 |
84 | render() {
85 | let hide = this.hide();
86 | let outOfRange = this.isOutOfRange();
87 | let clazz = `mode-group ${ hide ? 'hide' : 'show'}`;
88 | let tips = outOfRange ? '' : 'Click to Toggle Base/Sign Converter';
89 | let numClazz = `cm-number ${outOfRange ? '' : 'toggle-number'}`;
90 | return (
91 |
92 | {this.toIntString(this.props.int)}
93 |
94 | b
95 | o
96 | d
97 | x
98 |
99 |
100 | s
101 | u
102 |
103 |
104 | );
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/components/ReplOutputPromise.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {EOL} from 'os';
3 | import ReplCommon from '../common/ReplCommon';
4 | import ReplOutput from '../common/ReplOutput';
5 | import ReplConstants from '../constants/ReplConstants';
6 | import ReplOutputObject from './ReplOutputObject';
7 | import _ from 'lodash';
8 | import ReplActions from '../actions/ReplActions';
9 |
10 | export default class ReplOutputPromise extends React.Component {
11 | constructor(props) {
12 | super(props);
13 | this.state = {
14 | status: this.props.initStatus,
15 | value: this.props.initValue,
16 | reason: null,
17 | collapse: true
18 | };
19 |
20 | this.resolve = this.resolve.bind(this);
21 | this.onToggleCollapse = this.onToggleCollapse.bind(this);
22 | this.bindObjectToContext = this.bindObjectToContext.bind(this);
23 | }
24 |
25 | componentDidMount() {
26 | this.resolve();
27 | }
28 |
29 | shouldComponentUpdate(nextProps, nextState) {
30 | return !(_.isEqual(nextState, this.state) && _.isEqual(nextProps, this.props));
31 | }
32 |
33 | onToggleCollapse() {
34 | this.setState({
35 | collapse: !this.state.collapse
36 | });
37 | }
38 |
39 | resolve() {
40 | let promise = this.props.promise;
41 | promise.then((value) => {
42 | this.setState({
43 | value: value,
44 | status: ReplConstants.PROMISE.RESOLVED
45 | });
46 | }).catch((reason) => {
47 | this.setState({
48 | value: reason,
49 | status: ReplConstants.PROMISE.REJECTED
50 | });
51 | });
52 | }
53 |
54 | bindObjectToContext() {
55 | ReplActions.bindObjectToContext(this.props.promise, ReplOutput.transformObject(this.props.promise));
56 | }
57 |
58 | render() {
59 | let label = ' Promise {}';
60 |
61 | return (
62 |
63 | {
64 | this.state.collapse
65 | ?
66 |
67 |
68 |
69 | :
70 |
71 |
72 |
73 |
74 | {
75 |
76 | {
77 |
78 | [[PromiseStatus]]
79 | :
80 | {this.state.status}
81 |
82 | }
83 |
84 | }
85 | {
86 |
87 | {
88 |
89 | [[PromiseValue]]
90 | :
91 |
92 | }
93 | { ReplOutput.transformObject(this.state.value) }
94 |
95 | }
96 | {
97 | this.props.promise.__proto__
98 | ?
99 | __proto__
100 | :
101 |
102 |
103 | : null
104 | }
105 |
106 |
107 | }
108 | );
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/src/components/ReplOutputRegex.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 | import ReplDOM from '../common/ReplDOM';
4 | import ReplDOMEvents from '../common/ReplDOMEvents';
5 | import ReplActions from '../actions/ReplActions';
6 | import ReplOutput from '../common/ReplOutput';
7 |
8 | export default class ReplOutputRegex extends React.Component {
9 | constructor(props) {
10 | super(props);
11 | this.state = {
12 | collapse: true,
13 | input: ''
14 | }
15 |
16 | this.onToggleCollapse = this.onToggleCollapse.bind(this);
17 | this.onKeyUp = this.onKeyUp.bind(this);
18 | this.onHighlight = this.onHighlight.bind(this);
19 | this.bindObjectToContext = this.bindObjectToContext.bind(this);
20 | }
21 |
22 | shouldComponentUpdate(nextProps, nextState) {
23 | return !(_.isEqual(nextState, this.state) && _.isEqual(nextProps, this.props));
24 | }
25 |
26 | componentDidMount() {
27 | this.element = React.findDOMNode(this);
28 | }
29 |
30 | onToggleCollapse() {
31 | this.setState({
32 | collapse: !this.state.collapse
33 | });
34 | }
35 |
36 | onHighlight() {
37 | let re = this.props.regex;
38 | let replacer = (match) => {
39 | return match.length ? `${match} ` : ' ';
40 | };
41 | return this.state.input.replace(re, replacer);
42 | }
43 |
44 | onKeyUp(e) {
45 | if(e.shiftKey) { return; }
46 | let playGround = this.element.querySelector('.repl-regex-play-ground');
47 | this.state.input = playGround.innerText;
48 | let cursor = ReplDOM.getCursorPositionRelativeTo(playGround);
49 | let output = this.onHighlight();
50 | playGround.innerHTML = output;
51 | ReplDOM.setCursorPositionRelativeTo(cursor, playGround);
52 | }
53 |
54 | bindObjectToContext() {
55 | ReplActions.bindObjectToContext(this.props.regex, ReplOutput.transformObject(this.props.regex));
56 | }
57 |
58 | render() {
59 | return (
60 |
61 | {
62 | this.state.collapse
63 | ?
64 |
65 | {this.props.regex.toString()}
66 |
67 | :
68 |
69 | {this.props.regex.toString()}
70 |
71 | {
72 |
76 |
77 | }
78 |
79 | }
80 |
81 | );
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/components/ReplOutputString.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReplConstants from '../constants/ReplConstants';
3 | import _ from 'lodash';
4 |
5 | export default class ReplOutputString extends React.Component {
6 | constructor(props) {
7 | super(props);
8 | this.state = {
9 | collapse: true
10 | };
11 |
12 | const str = this.props.str;
13 | let len = str.length;
14 | let limit = this.props.limit || ReplConstants.OUTPUT_TRUNCATE_LENGTH;
15 | this.collapsable = len > limit - 1;
16 | if(this.collapsable) {
17 | this.prefix = str.slice(0, limit/2);
18 | this.suffix = str.slice(Math.max(limit/2, len - (limit/2)));
19 | }
20 | this.onToggleCollapse = this.onToggleCollapse.bind(this);
21 | }
22 |
23 | shouldComponentUpdate(nextProps, nextState) {
24 | return !(_.isEqual(nextState, this.state) && _.isEqual(nextProps, this.props));
25 | }
26 |
27 | onToggleCollapse() {
28 | this.setState({
29 | collapse: !this.state.collapse
30 | });
31 | }
32 |
33 | render() {
34 | return (
35 |
36 | {
37 | this.collapsable
38 | ? this.state.collapse
39 | ?
40 |
41 | "{this.prefix}
42 | {this.suffix}"
43 |
44 | :
45 |
46 | "{this.props.str}"
47 |
48 | :
49 | "{this.props.str}"
50 |
51 | }
52 |
53 | );
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/components/ReplOutputTranspile.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {EOL} from 'os';
3 | import ReplCommon from '../common/ReplCommon';
4 | import ReplConstants from '../constants/ReplConstants';
5 | import _ from 'lodash';
6 |
7 | export default class ReplOutputTranspile extends React.Component {
8 | constructor(props) {
9 | super(props);
10 | this.state = {
11 | collapse: true,
12 | };
13 | this.onToggleCollapse = this.onToggleCollapse.bind(this);
14 |
15 | let lines = this.props.output.trim().split(EOL);
16 | if(lines.length > 1 || lines[0].length > ReplConstants.COMMAND_TRUNCATE_LENGTH){
17 | this.shortEntry = ReplCommon.highlight(lines[0].slice(0, ReplConstants.COMMAND_TRUNCATE_LENGTH));
18 | }
19 | }
20 |
21 | shouldComponentUpdate(nextProps, nextState) {
22 | return !(_.isEqual(nextState, this.state) && _.isEqual(nextProps, this.props));
23 | }
24 |
25 | onToggleCollapse() {
26 | this.setState({
27 | collapse: !this.state.collapse
28 | });
29 | }
30 |
31 | render() {
32 | return (
33 |
34 | {
35 | this.shortEntry
36 | ? this.state.collapse
37 | ?
38 |
39 |
40 |
41 |
42 | :
43 |
44 |
45 |
46 |
47 | :
48 |
49 |
50 |
51 | }
52 |
53 | );
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/components/ReplOutputURL.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {shell} from 'electron';
3 | import ReplCommon from '../common/ReplCommon';
4 | import url from 'url';
5 | import _ from 'lodash';
6 |
7 | export default class ReplOutputURL extends React.Component {
8 | constructor(props) {
9 | super(props);
10 | this.openExternalFile = this.openExternalFile.bind(this);
11 | }
12 |
13 | shouldComponentUpdate(nextProps, nextState) {
14 | return !_.isEqual(nextProps, this.props);
15 | }
16 |
17 | openExternalFile() {
18 | let u = url.parse(this.props.url);
19 | if(u.protocol) {
20 | shell.openExternal(this.props.url);
21 | } else if(ReplCommon.isFile(this.props.url)) {
22 | shell.openExternal(`file://${this.props.url}`);
23 | } else {
24 | shell.openExternal(`http://${this.props.url}`);
25 | }
26 | }
27 | render() {
28 | return (
29 |
30 | {
31 |
32 | {this.props.url}
33 |
34 |
35 | }
36 |
37 | );
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/components/ReplPageZoom.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 | import ReplPreferencesActions from '../actions/ReplPreferencesActions';
4 |
5 | const zoomOptions = [0.75, 0.9, 1, 1.1, 1.2, 1.25, 1.3, 1.4, 1.5, 1.6, 1.7, 1.75, 1.8, 1.9, 2, 2.1, 2.2, 2.25, 2.3, 2.4, 2.5];
6 | export default class ReplPageZoom extends React.Component {
7 | constructor(props) {
8 | super(props);
9 | this.onChangePageZoomFactor = this.onChangePageZoomFactor.bind(this);
10 | this.getZoomPercentage = this.getZoomPercentage.bind(this);
11 | }
12 |
13 | onChangePageZoomFactor(e) {
14 | ReplPreferencesActions.changePageZoomFactor(parseFloat(e.target.value));
15 | }
16 |
17 | getZoomPercentage(zoom) {
18 | return `${(zoom * 100).toFixed()}%`;
19 | }
20 | render() {
21 | let zoom = global.Mancy.preferences.pageZoomFactor;
22 | return (
23 |
24 |
25 | Page zoom
26 |
27 |
28 |
29 | {
30 | _.map(zoomOptions, (z) => {
31 | return {this.getZoomPercentage(z)}
32 | })
33 | }
34 |
35 |
36 |
37 | );
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/components/ReplPrompt.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReplActiveIcon from './ReplActiveIcon';
3 | import ReplActiveInput from './ReplActiveInput';
4 |
5 | export default class ReplPrompt extends React.Component {
6 | constructor(props) {
7 | super(props);
8 | }
9 | render() {
10 | let key = this.props.tag || `prompt-${(Math.random() * Math.pow(10, 9)) | 0}`;
11 | return (
12 |
13 |
14 |
22 |
23 | );
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/components/ReplSourceFile.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {shell} from 'electron';
3 | import ReplCommon from '../common/ReplCommon';
4 | import ReplActiveInput from '../components/ReplActiveInput';
5 |
6 | export default class ReplSourceFile extends React.Component {
7 | constructor(props) {
8 | super(props);
9 | this.openExternalFile = this.openExternalFile.bind(this);
10 | }
11 | openExternalFile() {
12 | shell.openItem(this.props.location);
13 | }
14 | render() {
15 | let isNativeModule = false;
16 | if(!this.props.location) {
17 | const nativeModules = ReplCommon.getNativeModules(ReplActiveInput.getRepl().context);
18 | isNativeModule = nativeModules.indexOf(this.props.name) !== -1;
19 | }
20 |
21 | return (
22 |
23 | {
24 | this.props.location
25 | ?
26 |
27 | {this.props.name}
28 |
29 |
30 | :
31 | (
32 | isNativeModule
33 | ? '{this.props.name}' is native module
34 | : Unable to find source file for '{this.props.name}' module
35 | )
36 | }
37 |
38 | );
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/components/__mocks__/clipboard.js:
--------------------------------------------------------------------------------
1 |
2 | module.exports = {
3 | writeText: jest.genMockFunction(),
4 | readText: jest.genMockFunction(),
5 | readHTML: jest.genMockFunction(),
6 | writeHTML: jest.genMockFunction(),
7 | clear: jest.genMockFunction()
8 | };
9 |
--------------------------------------------------------------------------------
/src/components/__mocks__/shell.js:
--------------------------------------------------------------------------------
1 |
2 | module.exports = { beep: jest.genMockFunction() };
3 |
--------------------------------------------------------------------------------
/src/components/__tests__/ReplActiveIcon-test.js:
--------------------------------------------------------------------------------
1 |
2 | jest.dontMock('../ReplActiveIcon.js');
3 |
4 | describe('ReplActiveIcon', () => {
5 | let React = require('react/addons');
6 | let ReplActiveIcon = require('../ReplActiveIcon.js');
7 | let TestUtils = React.addons.TestUtils;
8 |
9 | it('should rendered properly', () => {
10 | let component = TestUtils.renderIntoDocument(
11 |
12 | );
13 | let icon = TestUtils.findRenderedDOMComponentWithTag(component, 'i');
14 | expect(React.findDOMNode(icon).className).toEqual('fa fa-angle-right');
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/src/components/__tests__/ReplConsole-test.js:
--------------------------------------------------------------------------------
1 | import { getStore } from '../../stores/ReplConsoleStore.js';
2 |
3 | jest.dontMock('../ReplConsole.js');
4 | describe('ReplConsole', () => {
5 | let React = require('react/addons');
6 | let ReplConsole = require('../ReplConsole.js');
7 | let TestUtils = React.addons.TestUtils;
8 |
9 | it('should render console entries', () => {
10 | let storeContent = { entries: [
11 | { type: 'error', data: 'Error msg', time: Math.random() },
12 | { type: 'warn', data: 'Warning msg', time: Math.random() },
13 | { type: 'info', data: 'Info msg', time: Math.random() },
14 | { type: 'log', data: 'Log msg', time: Math.random() },
15 | { type: 'debug', data: 'Debug msg', time: Math.random() }
16 | ]};
17 | getStore.mockReturnValue(storeContent);
18 |
19 | let component = TestUtils.renderIntoDocument( );
20 | expect(getStore).toBeCalled();
21 |
22 | let contents = TestUtils.scryRenderedDOMComponentsWithClass(component, 'repl-console-message-entry-content');
23 | expect(contents.length).toEqual(storeContent.entries.length);
24 |
25 | });
26 | });
27 |
--------------------------------------------------------------------------------
/src/components/__tests__/ReplConsoleMessageFilters-test.js:
--------------------------------------------------------------------------------
1 |
2 | jest.dontMock('../ReplConsoleMessageFilters.js');
3 |
4 | describe('ReplConsoleMessageFilters', () => {
5 | let React = require('react/addons');
6 | let ReplConsoleMessageFilters = require('../ReplConsoleMessageFilters.js');
7 | let TestUtils = React.addons.TestUtils;
8 | let labels = ['All', 'Error', 'Warning', 'Info', 'Log', 'Debug', 'Clear'];
9 | let displayLabels = ['A', 'E', 'W', 'I', 'L', 'D'];
10 |
11 | it('should render console labels', () => {
12 | let fun = jest.genMockFunction();
13 | let state = { all: true, error: true, warn: true, info: true, log: true, debug: true };
14 | let component = TestUtils.renderIntoDocument(
15 |
24 | );
25 | let filters = TestUtils.scryRenderedDOMComponentsWithClass(component, 'message-filter');
26 | expect(filters.length).toBe(labels.length);
27 | filters.forEach((filter) => {
28 | let node = React.findDOMNode(filter);
29 | expect(labels.indexOf(node.title)).not.toBe(-1);
30 | });
31 | });
32 |
33 | it('should toggle labels', () => {
34 | let fun = jest.genMockFunction();
35 | let state = { all: false, error: true, warn: true, info: true, log: true, debug: true };
36 | let component = TestUtils.renderIntoDocument(
37 |
46 | );
47 | let filters = TestUtils.scryRenderedDOMComponentsWithTag(component, 'input');
48 | filters.forEach((filter, idx) => {
49 | let node = React.findDOMNode(filter);
50 | expect(node.disabled).toBe(false);
51 | expect(labels.indexOf(node.value)).not.toBe(-1);
52 | TestUtils.Simulate.change(node);
53 | expect(fun.mock.calls.length).toBe(idx + 1);
54 | });
55 | });
56 |
57 | it('should check display labels', () => {
58 | let fun = jest.genMockFunction();
59 | let state = { all: false, error: true, warn: true, info: true, log: true, debug: true };
60 | let component = TestUtils.renderIntoDocument(
61 |
70 | );
71 | let filters = TestUtils.scryRenderedDOMComponentsWithClass(component, 'label');
72 | filters.forEach((filter, idx) => {
73 | let node = React.findDOMNode(filter);
74 | expect(displayLabels.indexOf(node.textContent.trim())).not.toBe(-1);
75 | });
76 | });
77 |
78 | it('should click on clear', () => {
79 | let fun = jest.genMockFunction();
80 | let clear = jest.genMockFunction();
81 | let state = { all: false, error: true, warn: true, info: true, log: true, debug: true };
82 | let component = TestUtils.renderIntoDocument(
83 |
92 | );
93 | let action = TestUtils.findRenderedDOMComponentWithClass(component, 'fa-ban');
94 | TestUtils.Simulate.click(React.findDOMNode(action));
95 | expect(fun).not.toBeCalled();
96 | expect(clear).toBeCalled();
97 | expect(clear.mock.calls.length).toBe(1);
98 | });
99 | });
100 |
--------------------------------------------------------------------------------
/src/components/__tests__/ReplEntries-test.js:
--------------------------------------------------------------------------------
1 |
2 | jest.dontMock('../ReplEntries.js');
3 | jest.dontMock('../ReplEntry.js');
4 | jest.dontMock('md5');
5 |
6 | describe('ReplEntries', () => {
7 | let React = require('react/addons');
8 | let ReplEntries = require('../ReplEntries.js');
9 | let TestUtils = React.addons.TestUtils;
10 | let entries = [{
11 | formattedOutput: ' undefined ',
12 | plainCode: 'let name = "mancy"',
13 | status: true,
14 | command: 'let name = "mancy" '
15 | }];
16 |
17 | it('should rendered properly', () => {
18 | let component = TestUtils.renderIntoDocument(
19 |
20 | );
21 | let children = TestUtils.scryRenderedDOMComponentsWithClass(component, 'repl-entry');
22 | expect(children.length).toBe(entries.length);
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/src/components/__tests__/ReplEntry-test.js:
--------------------------------------------------------------------------------
1 | import ReplActions from '../../actions/ReplActions';
2 |
3 | jest.dontMock('../ReplEntry.js');
4 | jest.dontMock('../ReplEntryIcon.js');
5 | jest.dontMock('../ReplEntryStatus.js');
6 |
7 | describe('ReplEntry', () => {
8 | let React = require('react/addons');
9 | let ReplEntry = require('../ReplEntry.js');
10 | let TestUtils = React.addons.TestUtils;
11 | let entry = {
12 | formattedOutput: ' undefined ',
13 | plainCode: 'let name = "mancy"',
14 | status: true,
15 | command: 'let name = "mancy" '
16 | };
17 |
18 | it('should collapse', () => {
19 | let component = TestUtils.renderIntoDocument(
20 |
21 | );
22 | let icon = TestUtils.findRenderedDOMComponentWithClass(component, 'repl-entry-icon');
23 | let action = TestUtils.findRenderedDOMComponentWithTag(icon, 'i');
24 | TestUtils.Simulate.click(action);
25 | expect(ReplActions.toggleCommandEntryView).toBeCalled();
26 | });
27 |
28 | it('should toggle entry', () => {
29 | let component = TestUtils.renderIntoDocument(
30 |
31 | );
32 | let icon = TestUtils.findRenderedDOMComponentWithClass(component, 'fa fa-minus-circle');
33 | TestUtils.Simulate.click(icon);
34 | expect(ReplActions.toggleEntryView).toBeCalled();
35 | });
36 |
37 | it('should remove', () => {
38 | let component = TestUtils.renderIntoDocument(
39 |
40 | );
41 | let icon = TestUtils.findRenderedDOMComponentWithClass(component, 'fa-times-circle');
42 | TestUtils.Simulate.click(icon);
43 | expect(ReplActions.removeEntry).toBeCalled();
44 | });
45 |
46 | it('should reload prompt', () => {
47 | let component = TestUtils.renderIntoDocument(
48 |
49 | );
50 | let icon = TestUtils.findRenderedDOMComponentWithClass(component, 'repeat');
51 | TestUtils.Simulate.click(icon);
52 | expect(ReplActions.reloadPrompt).toBeCalled();
53 | });
54 |
55 | });
56 |
--------------------------------------------------------------------------------
/src/components/__tests__/ReplEntryIcon-test.js:
--------------------------------------------------------------------------------
1 |
2 | jest.dontMock('../ReplEntryIcon.js');
3 |
4 | describe('ReplEntryIcon', () => {
5 | let React = require('react/addons');
6 | let ReplEntryIcon = require('../ReplEntryIcon.js');
7 | let TestUtils = React.addons.TestUtils;
8 |
9 | it('should have expand icon', () => {
10 | let fun = jest.genMockFunction();
11 | let component = TestUtils.renderIntoDocument(
12 |
13 | );
14 | let icon = TestUtils.findRenderedDOMComponentWithTag(component, 'i');
15 | expect(React.findDOMNode(icon).title).toEqual('expand command');
16 |
17 | TestUtils.Simulate.click(icon);
18 | expect(fun).toBeCalled();
19 | });
20 |
21 | it('should have collapse icon', () => {
22 | let fun = jest.genMockFunction();
23 | let component = TestUtils.renderIntoDocument(
24 |
25 | );
26 | let icon = TestUtils.findRenderedDOMComponentWithTag(component, 'i');
27 | expect(React.findDOMNode(icon).title).toEqual('collapse command');
28 |
29 | TestUtils.Simulate.click(icon);
30 | expect(fun).toBeCalled();
31 | });
32 | });
33 |
--------------------------------------------------------------------------------
/src/components/__tests__/ReplEntryMessage-test.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash';
2 | import {highlight} from '../../common/ReplCommon.js';
3 | jest.dontMock('../ReplEntryMessage.js');
4 |
5 | describe('ReplEntryMessage', () => {
6 | let React = require('react/addons');
7 | let ReplEntryMessage = require('../ReplEntryMessage.js');
8 | let TestUtils = React.addons.TestUtils;
9 | let msg = {
10 | formattedOutput: ' undefined ',
11 | plainCode: 'let name = "mancy"',
12 | status: true,
13 | command: 'let name = "mancy" '
14 | };
15 |
16 | it('should display command', () => {
17 | let component = TestUtils.renderIntoDocument(
18 |
20 | );
21 | let command = TestUtils.findRenderedDOMComponentWithClass(component, 'repl-entry-message-command');
22 | let id = React.findDOMNode(command)._attributes['data-reactid']._valueForAttrModified;
23 | expect(id.endsWith('long')).toBe(true);
24 | TestUtils.findRenderedDOMComponentWithClass(component, 'repl-entry-message-output')
25 | });
26 |
27 | it('should display command with collapsed output', () => {
28 | let component = TestUtils.renderIntoDocument(
29 |
31 | );
32 | let command = TestUtils.scryRenderedDOMComponentsWithClass(component, 'repl-entry-message-output');
33 | expect(command.length).toBe(0);
34 | });
35 |
36 | it('should display with collapsed command', () => {
37 | let longMsg = _.extend(msg, {
38 | plainCode : "let fun = () => {\n return; \n}"
39 | });
40 | highlight.mockImpl(() => 'let fun = () => {');
41 | let component = TestUtils.renderIntoDocument(
42 |
44 | );
45 | TestUtils.findRenderedDOMComponentWithClass(component, 'ellipsis');
46 | });
47 |
48 |
49 | });
50 |
--------------------------------------------------------------------------------
/src/components/__tests__/ReplEntryOutputError-test.js:
--------------------------------------------------------------------------------
1 |
2 | jest.dontMock('../ReplEntryOutputError.js');
3 |
4 | describe('ReplEntryOutputError', () => {
5 | let React = require('react/addons');
6 | let ReplEntryOutputError = require('../ReplEntryOutputError.js');
7 | let TestUtils = React.addons.TestUtils;
8 | let error = 'name is not defined';
9 | let errorFile = 'repl.js';
10 | let errorFunction = 'REPLServer.defaultEval';
11 | let errorLine = '166';
12 | let errorColumn = '27';
13 | let msg = `ReferenceError: ${error}`;
14 | let trace = [`at ${errorFunction} (${errorFile}:${errorLine}:${errorColumn})`];
15 |
16 | it('should rendered properly', () => {
17 | let component = TestUtils.renderIntoDocument(
18 |
19 |
20 | );
21 | let errorMsg = TestUtils.findRenderedDOMComponentWithClass(component, 'repl-entry-output-error-message');
22 | let errorTraceFile = TestUtils.findRenderedDOMComponentWithClass(component, 'stack-error-file');
23 | let errorTraceFunction = TestUtils.findRenderedDOMComponentWithClass(component, 'stack-error-function');
24 | let errorTraceLine = TestUtils.findRenderedDOMComponentWithClass(component, 'stack-error-row');
25 | let errorTraceColumn = TestUtils.findRenderedDOMComponentWithClass(component, 'stack-error-column');
26 |
27 | expect(React.findDOMNode(errorMsg).textContent).toContain(error);
28 | expect(React.findDOMNode(errorTraceFile).textContent).toContain(errorFile);
29 | expect(React.findDOMNode(errorTraceFunction).textContent).toContain(errorFunction);
30 | expect(React.findDOMNode(errorTraceLine).textContent).toContain(errorLine);
31 | expect(React.findDOMNode(errorTraceColumn).textContent).toContain(errorColumn);
32 | });
33 | });
34 |
--------------------------------------------------------------------------------
/src/components/__tests__/ReplEntryStatus-test.js:
--------------------------------------------------------------------------------
1 |
2 | jest.dontMock('../ReplEntryStatus.js');
3 |
4 | describe('ReplEntryStatus', () => {
5 | let React = require('react/addons');
6 | let ReplEntryStatus = require('../ReplEntryStatus.js');
7 | let TestUtils = React.addons.TestUtils;
8 |
9 | it('should render entry status collapsed without error', () => {
10 | let fun = jest.genMockFunction();
11 | let component = TestUtils.renderIntoDocument(
12 |
16 | );
17 | let errorIcon = TestUtils.scryRenderedDOMComponentsWithClass(component, 'fa-exclamation-triangle');
18 | expect(errorIcon.length).toBe(0);
19 | let icon = TestUtils.findRenderedDOMComponentWithClass(component, 'plus');
20 | TestUtils.Simulate.click(icon);
21 | expect(fun).toBeCalled();
22 | });
23 |
24 | it('should render entry status expanded without error', () => {
25 | let fun = jest.genMockFunction();
26 | let component = TestUtils.renderIntoDocument(
27 |
31 | );
32 | let errorIcon = TestUtils.scryRenderedDOMComponentsWithClass(component, 'fa-exclamation-triangle');
33 | expect(errorIcon.length).toBe(0);
34 | let icon = TestUtils.findRenderedDOMComponentWithClass(component, 'minus');
35 | TestUtils.Simulate.click(icon);
36 | expect(fun).toBeCalled();
37 | });
38 |
39 | it('should render entry status with error', () => {
40 | let fun = jest.genMockFunction();
41 | let component = TestUtils.renderIntoDocument(
42 |
46 | );
47 | TestUtils.findRenderedDOMComponentWithClass(component, 'fa-exclamation-triangle');
48 | });
49 |
50 | it('should trigger reload', () => {
51 | let fun = jest.genMockFunction();
52 | let reload = jest.genMockFunction();
53 | let component = TestUtils.renderIntoDocument(
54 |
58 | );
59 | let icon = TestUtils.findRenderedDOMComponentWithClass(component, 'repeat');
60 | TestUtils.Simulate.click(icon);
61 | expect(reload).toBeCalled();
62 | expect(fun).not.toBeCalled();
63 | });
64 |
65 | it('should trigger remove', () => {
66 | let fun = jest.genMockFunction();
67 | let remove = jest.genMockFunction();
68 | let component = TestUtils.renderIntoDocument(
69 |
73 | );
74 | let icon = TestUtils.findRenderedDOMComponentWithClass(component, 'remove');
75 | TestUtils.Simulate.click(icon);
76 | expect(remove).toBeCalled();
77 | expect(fun).not.toBeCalled();
78 | });
79 |
80 | it('should trigger toggle', () => {
81 | let fun = jest.genMockFunction();
82 | let toggle = jest.genMockFunction();
83 | let component = TestUtils.renderIntoDocument(
84 |
88 | );
89 | let icon = TestUtils.findRenderedDOMComponentWithClass(component, 'minus');
90 | TestUtils.Simulate.click(icon);
91 | expect(toggle).toBeCalled();
92 | expect(fun).not.toBeCalled();
93 | });
94 |
95 | });
96 |
--------------------------------------------------------------------------------
/src/components/__tests__/ReplOutputArray-test.js:
--------------------------------------------------------------------------------
1 |
2 | jest.dontMock('../ReplOutputArray.js');
3 | jest.dontMock('../../common/ReplOutput.js');
4 |
5 | describe('ReplOutputArray', () => {
6 | let React = require('react/addons');
7 | let ReplOutputArray = require('../ReplOutputArray.js');
8 | let TestUtils = React.addons.TestUtils;
9 | let label = 'Array[7]';
10 | let arr = [0, true, 'yes', null, undefined, [1], {fun: () => {}}];
11 |
12 | it('should have collapsed array', () => {
13 | let component = TestUtils.renderIntoDocument(
14 |
15 | );
16 |
17 | let desc = TestUtils.findRenderedDOMComponentWithClass(component, 'array-desc');
18 | expect(React.findDOMNode(desc).textContent).toEqual(label);
19 | let entry = TestUtils.scryRenderedDOMComponentsWithClass(component, 'array-entry');
20 | expect(entry.length).toBe(0);
21 | });
22 |
23 | it('should expand array', () => {
24 | let component = TestUtils.renderIntoDocument(
25 |
26 | );
27 |
28 | let icon = TestUtils.findRenderedDOMComponentWithClass(component, 'fa-play');
29 | TestUtils.Simulate.click(icon);
30 |
31 | let entries = TestUtils.scryRenderedDOMComponentsWithClass(component, 'array-entry');
32 | expect(entries.length).toBe(arr.length);
33 | });
34 |
35 | });
36 |
--------------------------------------------------------------------------------
/src/components/__tests__/ReplOutputFunction-test.js:
--------------------------------------------------------------------------------
1 |
2 | jest.dontMock('../ReplOutputFunction.js');
3 | jest.dontMock('../../common/ReplOutput.js');
4 |
5 | describe('ReplOutputFunction', () => {
6 | let React = require('react/addons');
7 | let ReplOutputFunction = require('../ReplOutputFunction.js');
8 | let TestUtils = React.addons.TestUtils;
9 | let label = ' function() {}';
10 | let f = function test() {
11 | return 'test';
12 | };
13 | f.desc = 'testMe';
14 | let funElement = `
15 | function test() {
16 | return 'test' ;
17 | }
18 |
19 | `;
20 | let shortElement = `
21 | function test() {
22 |
23 | `;
24 |
25 | it('should have collapsed function', () => {
26 | let component = TestUtils.renderIntoDocument(
27 |
28 | );
29 |
30 | let desc = TestUtils.findRenderedDOMComponentWithClass(component, 'object-desc');
31 | expect(React.findDOMNode(desc).textContent).toEqual(label);
32 | let entry = TestUtils.scryRenderedDOMComponentsWithClass(component, 'object-entry');
33 | expect(entry.length).toBe(0);
34 | });
35 |
36 | it('should expand function', () => {
37 | let component = TestUtils.renderIntoDocument(
38 |
39 | );
40 |
41 | let icon = TestUtils.findRenderedDOMComponentWithClass(component, 'fa-play');
42 | TestUtils.Simulate.click(icon);
43 |
44 | let entries = TestUtils.scryRenderedDOMComponentsWithClass(component, 'object-entry');
45 | expect(entries.length).toBe(Object.getOwnPropertyNames(f).length);
46 | });
47 |
48 | it('should expand function source', () => {
49 | let component = TestUtils.renderIntoDocument(
50 |
51 | );
52 |
53 | let icon = TestUtils.findRenderedDOMComponentWithClass(component, 'fa-play');
54 | TestUtils.Simulate.click(icon);
55 |
56 | let source = TestUtils.findRenderedDOMComponentWithClass(component, 'fa-plus-square-o');
57 | TestUtils.Simulate.click(source);
58 |
59 | TestUtils.scryRenderedDOMComponentsWithClass(component, 'fa-minus-square-o');
60 | });
61 |
62 | });
63 |
--------------------------------------------------------------------------------
/src/components/__tests__/ReplOutputObject-test.js:
--------------------------------------------------------------------------------
1 |
2 | jest.dontMock('../ReplOutputObject.js');
3 | jest.dontMock('../../common/ReplOutput.js');
4 |
5 | describe('ReplOutputObject', () => {
6 | let React = require('react/addons');
7 | let ReplOutputObject = require('../ReplOutputObject.js');
8 | let TestUtils = React.addons.TestUtils;
9 | let label = ' Object {}';
10 | let o = { name: 'mancy' };
11 |
12 | it('should have collapsed object', () => {
13 | let component = TestUtils.renderIntoDocument(
14 |
15 | );
16 |
17 | let desc = TestUtils.findRenderedDOMComponentWithClass(component, 'object-desc');
18 | expect(React.findDOMNode(desc).textContent).toEqual(label);
19 | let entry = TestUtils.scryRenderedDOMComponentsWithClass(component, 'object-entry');
20 | expect(entry.length).toBe(0);
21 | });
22 |
23 | it('should expand object', () => {
24 | let component = TestUtils.renderIntoDocument(
25 |
26 | );
27 |
28 | let icon = TestUtils.findRenderedDOMComponentWithClass(component, 'fa-play');
29 | TestUtils.Simulate.click(icon);
30 |
31 | let entries = TestUtils.scryRenderedDOMComponentsWithClass(component, 'object-entry');
32 | expect(entries.length).toBe(Object.keys(o).length);
33 | });
34 |
35 | });
36 |
--------------------------------------------------------------------------------
/src/components/__tests__/ReplPrompt-test.js:
--------------------------------------------------------------------------------
1 |
2 | jest.dontMock('../ReplPrompt.js');
3 | jest.dontMock('../ReplActiveIcon.js');
4 | jest.dontMock('../ReplActiveInput.js');
5 | jest.dontMock('../../stores/ReplActiveInputStore.js');
6 |
7 | describe('ReplPrompt', () => {
8 | let React = require('react/addons');
9 | let ReplPrompt = require('../ReplPrompt.js');
10 | let TestUtils = React.addons.TestUtils;
11 |
12 | it('should rendered properly', () => {
13 | let component = TestUtils.renderIntoDocument(
14 |
21 | );
22 | let icon = TestUtils.findRenderedDOMComponentWithTag(component, 'i');
23 | expect(React.findDOMNode(icon).className).toEqual('fa fa-angle-right');
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/src/components/__tests__/ReplStatusBar-test.js:
--------------------------------------------------------------------------------
1 |
2 | jest.dontMock('../ReplStatusBar.js');
3 |
4 | describe('ReplStatusBar', () => {
5 | let React = require('react/addons');
6 | let ReplStatusBar = require('../ReplStatusBar.js');
7 | let TestUtils = React.addons.TestUtils;
8 | let entries = [
9 | { status: false },
10 | { status: true },
11 | { status: true },
12 | { status: true },
13 | { status: false }
14 | ];
15 |
16 | it('should show counts & mode', () => {
17 | let fun = jest.genMockFunction();
18 | let component = TestUtils.renderIntoDocument(
19 |
24 | );
25 | let command = TestUtils.findRenderedDOMComponentWithClass(component, 'repl-status-bar-commands');
26 | let error = TestUtils.findRenderedDOMComponentWithClass(component, 'repl-status-bar-errors');
27 | let mode = TestUtils.findRenderedDOMComponentWithClass(component, 'repl-status-bar-mode');
28 |
29 | expect(React.findDOMNode(command).textContent).toEqual('3');
30 | expect(React.findDOMNode(error).textContent).toEqual('2');
31 | expect(React.findDOMNode(mode).textContent).toEqual('magic');
32 | });
33 |
34 | it('should show console bell', () => {
35 | let fun = jest.genMockFunction();
36 | let component = TestUtils.renderIntoDocument(
37 |
42 | );
43 | TestUtils.findRenderedDOMComponentWithClass(component, 'console-notification');
44 | });
45 |
46 | it('should toggle console', () => {
47 | let fun = jest.genMockFunction();
48 | let component = TestUtils.renderIntoDocument(
49 |
54 | );
55 | let console = TestUtils.findRenderedDOMComponentWithClass(component, 'repl-status-bar-console');
56 | TestUtils.Simulate.click(console);
57 | expect(fun).toBeCalled();
58 | });
59 |
60 | it('should show console', () => {
61 | let fun = jest.genMockFunction();
62 | let component = TestUtils.renderIntoDocument(
63 |
68 | );
69 | TestUtils.findRenderedDOMComponentWithClass(component, 'text-danger');
70 | });
71 | });
72 |
--------------------------------------------------------------------------------
/src/components/clojurescript/ReplOutputCljsDoc.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 |
4 | export default class ReplOutputCljsDoc extends React.Component {
5 | constructor(props) {
6 | super(props);
7 | this.state = {
8 | collapse: !!this.props.open,
9 | };
10 |
11 | this.onToggleCollapse = this.onToggleCollapse.bind(this);
12 | }
13 |
14 | shouldComponentUpdate(nextProps, nextState) {
15 | return !(_.isEqual(nextState, this.state) && _.isEqual(nextProps, this.props));
16 | }
17 |
18 | onToggleCollapse() {
19 | this.setState({
20 | collapse: !this.state.collapse
21 | });
22 | }
23 |
24 | render() {
25 | let clazz = this.state.collapse ? 'fa fa-minus-square-o' : 'fa fa-plus-square-o';
26 | return (
27 |
28 | {
29 |
30 |
31 | {this.props.name}
32 | {
33 | this.state.collapse
34 | ?
35 |
36 |
37 | {this.props.description}
38 |
39 |
40 | : null
41 | }
42 |
43 | }
44 |
45 | );
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/components/clojurescript/ReplOutputCljsDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 |
4 | export default class ReplOutputCljsDocs extends React.Component {
5 | constructor(props) {
6 | super(props);
7 | this.state = {
8 | collapse: true,
9 | };
10 |
11 | this.onToggleCollapse = this.onToggleCollapse.bind(this);
12 | }
13 |
14 | shouldComponentUpdate(nextProps, nextState) {
15 | return !(_.isEqual(nextState, this.state) && _.isEqual(nextProps, this.props));
16 | }
17 |
18 | onToggleCollapse() {
19 | this.setState({
20 | collapse: !this.state.collapse
21 | });
22 | }
23 |
24 | render() {
25 | let clazz = this.state.collapse ? 'fa fa-minus-square-o' : 'fa fa-plus-square-o';
26 | return (
27 |
28 | {
29 |
30 |
31 | Documentation Viewer
32 | {this.state.collapse ? this.props.docs : null}
33 |
34 | }
35 |
36 | );
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/components/clojurescript/ReplOutputCljsFun.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReplOutput from '../../common/ReplOutput';
3 |
4 | export default class ReplOutputCljsVal extends React.Component {
5 | constructor(props) {
6 | super(props);
7 | const type = this.props.token.type;
8 | const parts = type.split(/[\s.]/);
9 | this.type = parts[parts.length - 1];
10 | }
11 |
12 | render() {
13 | return (
14 |
15 | {this.props.token.prefix}
16 | {
17 | this.props.token.keywordPrefix
18 | ? {this.props.token.keywordPrefix}
19 | : null
20 | }
21 | {this.props.value}
22 | {this.props.token.suffix}
23 | {this.type}
24 |
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/components/clojurescript/ReplOutputCljsMeta.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 | import ReplOutput from '../../common/ReplOutput';
4 |
5 | export default class ReplOutputCljsMeta extends React.Component {
6 | constructor(props) {
7 | super(props);
8 | this.state = {
9 | iCollapse: true,
10 | collapse: true
11 | };
12 |
13 | this.onToggleCollapse = this.onToggleCollapse.bind(this);
14 | this.onToggleICollapse = this.onToggleICollapse.bind(this);
15 | this.getMetaData = this.getMetaData.bind(this);
16 | this.buildMetaData = this.buildMetaData.bind(this);
17 | }
18 |
19 | shouldComponentUpdate(nextProps, nextState) {
20 | return !(_.isEqual(nextState, this.state) && _.isEqual(nextProps, this.props));
21 | }
22 |
23 | onToggleCollapse() {
24 | this.setState({
25 | collapse: !this.state.collapse
26 | });
27 | }
28 |
29 | onToggleICollapse() {
30 | this.setState({
31 | iCollapse: !this.state.iCollapse
32 | });
33 | }
34 |
35 | buildMetaData(arr, result = []) {
36 | for(let pos = 0; pos + 1 < arr.length; pos += 2) {
37 | // revisit
38 | if(!arr[pos] && !arr[pos + 1]) { return result; }
39 | if(arr[pos] === null) { this.buildMetaData(arr[pos + 1].arr, result); }
40 | else {
41 | result.push(
42 |
43 | {arr[pos].toString()}
44 | {ReplOutput.clojure(arr[pos + 1]).view()}
45 |
46 | );
47 | }
48 | }
49 | return result;
50 | }
51 |
52 | getMetaData(arr) {
53 | let metaRecords = this.buildMetaData(arr);
54 | return (
55 |
56 | {_.map(metaRecords, r => r)}
57 |
58 | );
59 | }
60 |
61 | render() {
62 | const value = this.props.value || {};
63 | const core = this.props.core;
64 | const iMeta = value._meta;
65 | const meta = value.meta;
66 | return (
67 |
68 | {
69 | iMeta
70 | ? this.state.iCollapse
71 | ?
72 |
73 | root
74 |
75 | :
76 |
77 | root
78 | {this.getMetaData(iMeta.root.arr)}
79 |
80 | : null
81 | }
82 | {
83 | meta
84 | ? this.state.collapse
85 | ?
86 |
87 | meta
88 |
89 | :
90 |
91 | meta
92 | {this.getMetaData(meta.arr)}
93 |
94 | : null
95 | }
96 |
97 | );
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/components/clojurescript/ReplOutputCljsSeq.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 | import ReplOutput from '../../common/ReplOutput';
4 | import ReplConstants from '../../constants/ReplConstants';
5 |
6 | export default class ReplOutputCljsSeq extends React.Component {
7 | constructor(props) {
8 | super(props);
9 | this.state = {
10 | collapse: true
11 | }
12 | const type = this.props.token.type;
13 | const parts = type.split(/[\s.]/);
14 | this.type = parts[parts.length - 1];
15 | this.onToggleCollapse = this.onToggleCollapse.bind(this);
16 | }
17 |
18 | shouldComponentUpdate(nextProps, nextState) {
19 | return !(_.isEqual(nextState, this.state) && _.isEqual(nextProps, this.props));
20 | }
21 |
22 | onToggleCollapse() {
23 | this.setState({
24 | collapse: !this.state.collapse
25 | });
26 | }
27 |
28 | getKeysButLength() {
29 | let keys = Object.keys(this.props.array);
30 | return keys.slice(0, keys.length);
31 | }
32 |
33 | getShortSeq() {
34 | const arr = this.props.array;
35 | const SHORT_LEN = ReplConstants.CLJS_SEQ_TRUNCATE_LENGTH;
36 | const element =
37 |
38 | {this.props.token.prefix}
39 | {this.getSeqRecords(Math.min(arr.length, SHORT_LEN))}
40 | {
41 | arr.length > SHORT_LEN
42 | ?
43 | : null
44 | }
45 | {this.props.token.suffix}
46 |
47 |
48 | return {short: arr.length <= SHORT_LEN, element: element};
49 | }
50 |
51 | buildMapData(arr, result = []) {
52 | for(let pos = 0; pos + 1 < arr.length; pos += 2) {
53 | const key = arr[pos];
54 | const value = arr[pos + 1];
55 | result.push(
56 |
57 | {key.toString()}
58 |
59 | { value && value._isReactElement ? {value} : ReplOutput.clojure(value).view() }
60 |
61 |
62 | );
63 | }
64 | return result;
65 | }
66 |
67 |
68 | getSeqRecords(len = -1) {
69 | const clazz = `${len !== -1 ? 'inline' : ''} array-rec`;
70 | const type = this.type;
71 | const mapType = this.props.token.arity === 2;
72 | let keys = this.getKeysButLength();
73 | keys = len !== -1 ? keys.slice(0, len) : keys;
74 | return (
75 |
76 | {
77 | !mapType
78 | ? _.map(keys, (key) => {
79 | let value = this.props.array[key];
80 | let idx = parseInt(key, 10);
81 | return (
82 |
83 | { len === -1 ? {this.props.start + idx}: : null}
84 | { value && value._isReactElement ? {value} : ReplOutput.clojure(value).view() }
85 |
86 | )
87 | })
88 | : this.buildMapData(this.props.array.slice(0, keys.length))
89 | }
90 |
91 | );
92 | }
93 |
94 | render() {
95 | const {short, element} = this.getShortSeq();
96 | const title = this.props.length || "";
97 | return (
98 |
99 | {
100 | short
101 | ?
102 | {element}
103 | {this.type}
104 |
105 | : this.state.collapse
106 | ?
107 |
108 | {element}
109 | {this.type}
110 |
111 | :
112 |
113 | {element}
114 | {this.type}
115 | {this.getSeqRecords()}
116 |
117 | }
118 |
119 | );
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/src/components/clojurescript/ReplOutputCljsSource.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 |
4 | export default class ReplOutputCljsVar extends React.Component {
5 | constructor(props) {
6 | super(props);
7 | this.state = {
8 | collapse: true,
9 | };
10 |
11 | this.onToggleCollapse = this.onToggleCollapse.bind(this);
12 | }
13 |
14 | shouldComponentUpdate(nextProps, nextState) {
15 | return !(_.isEqual(nextState, this.state) && _.isEqual(nextProps, this.props));
16 | }
17 |
18 | onToggleCollapse() {
19 | this.setState({
20 | collapse: !this.state.collapse
21 | });
22 | }
23 |
24 | render() {
25 | return (
26 |
27 | {
28 | this.state.collapse
29 | ?
30 |
31 | {this.props.short}
32 |
33 | :
34 |
35 |
36 |
37 |
38 | }
39 |
40 | );
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/components/clojurescript/ReplOutputCljsVal.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReplOutput from '../../common/ReplOutput';
3 |
4 | export default class ReplOutputCljsVal extends React.Component {
5 | constructor(props) {
6 | super(props);
7 | const type = this.props.token.type;
8 | const parts = type.split(/[\s.]/);
9 | this.type = parts[parts.length - 1];
10 | }
11 |
12 | render() {
13 | return (
14 |
15 | {this.props.token.prefix}
16 | {
17 | this.props.token.keywordPrefix
18 | ? {this.props.token.keywordPrefix}
19 | : null
20 | }
21 | {this.props.value}
22 | {this.props.token.suffix}
23 | {this.type}
24 |
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/components/clojurescript/ReplOutputCljsVar.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 | import ReplOutput from '../../common/ReplOutput';
4 |
5 | export default class ReplOutputCljsVar extends React.Component {
6 | constructor(props) {
7 | super(props);
8 | this.state = {
9 | collapse: true
10 | };
11 |
12 | this.onToggleCollapse = this.onToggleCollapse.bind(this);
13 | }
14 |
15 | shouldComponentUpdate(nextProps, nextState) {
16 | return !(_.isEqual(nextState, this.state) && _.isEqual(nextProps, this.props));
17 | }
18 |
19 | onToggleCollapse() {
20 | this.setState({
21 | collapse: !this.state.collapse
22 | });
23 | }
24 |
25 | getValue() {
26 | try {
27 | return this.props.value.val();
28 | } catch(e) {
29 | // revist: something went wrong!
30 | return e.message;
31 | }
32 | }
33 |
34 | render() {
35 | return (
36 |
37 | {
38 | this.state.collapse
39 | ?
40 |
41 | #
42 | '
43 | {this.props.value.sym.str}
44 |
45 | :
46 |
47 | #
48 | '
49 | {this.props.value.sym.str}
50 |
51 | {ReplOutput.clojure(this.getValue()).view()}
52 |
53 |
54 | }
55 |
56 | );
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/components/clojurescript/ReplOutputCljsWrapper.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReplOutput from '../../common/ReplOutput';
3 | import ReplCommon from '../../common/ReplCommon';
4 | import ReplOutputCljsMeta from './ReplOutputCljsMeta';
5 | import ReplOutputGridViewer from '../ReplOutputGridViewer'
6 | import ReplOutputChartViewer from '../ReplOutputChartViewer'
7 |
8 | export default class ReplOutputCljsWrapper extends React.Component {
9 | constructor(props) {
10 | super(props);
11 | this.state = {
12 | collapse: true
13 | };
14 |
15 | if(this.props.value) {
16 | const value = this.props.value;
17 | this.hasMeta = value.meta || value._meta;
18 |
19 | this.jsValue = this.props.core.clj__GT_js(value);
20 | try{ this.hasGrid = ReplCommon.candidateForGrid(this.jsValue); }
21 | catch(e) { this.hasGrid = false; }
22 | this.hasChart = ReplCommon.candidateForChart(this.jsValue);
23 | }
24 | this.hasExtra = this.hasMeta || this.hasGrid || this.hasChart;
25 | this.onToggleCollapse = this.onToggleCollapse.bind(this);
26 | }
27 |
28 | onToggleCollapse() {
29 | this.setState({
30 | collapse: !this.state.collapse
31 | });
32 | }
33 |
34 | getMeta() {
35 | return ((!this.state.collapse && this.hasMeta)
36 | ?
37 | : null);
38 | }
39 |
40 | getGrid() {
41 | return ((!this.state.collapse && this.hasGrid)
42 | ?
43 |
44 |
45 | : null);
46 | }
47 |
48 | getChart() {
49 | return ((!this.state.collapse && this.hasChart)
50 | ?
51 |
52 |
53 | : null);
54 | }
55 |
56 | render() {
57 | const clazz = `fa fa-${this.state.collapse ? 'plus' : 'minus'}-square-o`;
58 | return (
59 |
60 | {
61 | this.hasExtra
62 | ?
63 |
64 | {this.props.view}
65 | {this.getMeta()}
66 | {this.getGrid()}
67 | {this.getChart()}
68 |
69 | : this.props.view
70 | }
71 |
72 | );
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/constants/ReplConstants.js:
--------------------------------------------------------------------------------
1 | const ReplConstants = {
2 | REPL_HISTORY_SIZE: 1000,
3 | REPL_ENCODING: 'utf8',
4 | TAB_WIDTH: 2,
5 | COMMAND_TRUNCATE_LENGTH: 80,
6 | OUTPUT_TRUNCATE_LENGTH: 80,
7 | CLJS_SEQ_TRUNCATE_LENGTH: 10,
8 | PROMISE: {
9 | PENDING: 'pending',
10 | RESOLVED: 'fulfilled',
11 | REJECTED: 'rejected',
12 | },
13 | REPL_HISTORY_SUGGESTION: 200,
14 | BABEL_OPTIONS: {
15 | "plugins": [
16 | "transform-es2015-classes",
17 | "transform-es2015-computed-properties",
18 | "transform-es2015-destructuring",
19 | "transform-es2015-for-of",
20 | "transform-es2015-function-name",
21 | "transform-es2015-object-super",
22 | "transform-es2015-parameters",
23 | "transform-es2015-sticky-regex",
24 | "transform-es2015-unicode-regex",
25 | "transform-regenerator",
26 | "transform-do-expressions",
27 | "transform-function-bind",
28 | "transform-class-constructor-call",
29 | "transform-class-properties",
30 | "transform-decorators",
31 | "transform-export-extensions",
32 | "syntax-trailing-function-commas",
33 | "transform-object-rest-spread",
34 | "transform-async-to-generator",
35 | "transform-exponentiation-operator",
36 | "syntax-flow",
37 | "syntax-jsx",
38 | "transform-flow-strip-types",
39 | "transform-react-jsx",
40 | "transform-runtime"
41 | ],
42 | "highlightCode": false,
43 | "filename": `${__dirname}/mancy-repl`,
44 | "env": process.env,
45 | "retainLines": true,
46 | "ast": false,
47 | "babelrc": false,
48 | },
49 | EXEC_TIMEOUT: 60000,
50 | IFRAME_MAX_HEIGHT: 500,
51 | REPL_WATERMARK_LOGO: '>_',
52 | REPL_WATERMARK_MSG: 'REPL for fun 🙈',
53 | };
54 |
55 | export default ReplConstants;
56 |
--------------------------------------------------------------------------------
/src/languages/ReplLangWrapper.js:
--------------------------------------------------------------------------------
1 | import {Readable, Writable} from 'stream';
2 | import ReplContext from '../common/ReplContext';
3 | import ReplConstants from '../constants/ReplConstants';
4 | import ReplOutput from '../common/ReplOutput';
5 | import {EOL} from 'os';
6 | import fs from 'fs';
7 |
8 | import jsREPL from 'repl';
9 | import coffeeREPL from 'coffee-script/repl';
10 | import tsREPL from './ReplTypeScript';
11 | import lsREPL from './ReplLiveScript';
12 | import cljsREPL from './ReplClojureScript';
13 |
14 | const REPL = (repl) => {
15 | let readable = new Readable();
16 | let writable = new Writable();
17 |
18 | readable._read = writable.write = () => {};
19 |
20 | let nodeRepl = repl.start({
21 | prompt: '',
22 | input: readable,
23 | output: writable,
24 | terminal: false,
25 | useGlobal: false,
26 | ignoreUndefined: false,
27 | useColors: false,
28 | writer: (obj, opt) => {
29 | nodeRepl.$lastExpression = ReplOutput.some(obj);
30 | // link context
31 | nodeRepl.context = ReplContext.getContext();
32 | return '<>';
33 | },
34 | historySize: ReplConstants.REPL_HISTORY_SIZE,
35 | replMode: repl['REPL_MODE_MAGIC'],
36 | });
37 |
38 | // remove default repl commands
39 | ['clear', 'help', 'save', 'exit'].forEach(cmd => delete nodeRepl.commands[cmd]);
40 |
41 | // here is our sandbox environment
42 | nodeRepl.context = ReplContext.getContext();
43 |
44 | return {
45 | getREPL: () => nodeRepl,
46 | setREPL: () => ReplContext.hookContext((context) => { nodeRepl.context = context; }),
47 | repl
48 | };
49 | };
50 |
51 | // remove loadAction function after below PR pushed and is available in electron based node.
52 | // lib/repl.js with below PR
53 | // https://github.com/nodejs/node/pull/4170
54 | let replJS = REPL(jsREPL);
55 | let loadAction = function(file) {
56 | try {
57 | let stats = fs.statSync(file);
58 | if (stats && stats.isFile()) {
59 | let self = this;
60 | let data = fs.readFileSync(file, 'utf8');
61 | let lines = data.split('\n');
62 | this.displayPrompt();
63 | lines.forEach(function(line) {
64 | if (line) {
65 | self.write(line + '\n');
66 | }
67 | });
68 | } else {
69 | this.outputStream.write('Failed to load:' + file + ' is not a valid file\n');
70 | }
71 | } catch (e) {
72 | this.outputStream.write('Failed to load:' + file + '\n');
73 | }
74 | this.displayPrompt();
75 | };
76 | replJS.getREPL().commands.load.action = loadAction;
77 |
78 | export default {
79 | js: replJS,
80 | coffee: REPL(coffeeREPL),
81 | ts: REPL(tsREPL),
82 | ls: REPL(lsREPL),
83 | cljs: REPL(cljsREPL),
84 | };
85 |
--------------------------------------------------------------------------------
/src/languages/ReplLanguages.js:
--------------------------------------------------------------------------------
1 | import {js, coffee, ts, ls, cljs} from './ReplLangWrapper';
2 |
3 | // node repl wrappers
4 | const langs = {
5 | js,
6 | coffee,
7 | ts,
8 | ls,
9 | cljs,
10 | };
11 |
12 | const repls = Object.keys(langs).map(l => langs[l].getREPL());
13 |
14 | let repl = langs.js;
15 | repl.setREPL();
16 |
17 | const getREPL = () => {
18 | return repl.getREPL();
19 | }
20 |
21 | // being used for repl mode
22 | const getREPLProvider = () => {
23 | return langs.js.repl;
24 | }
25 |
26 | const setREPL = (name) => {
27 | if(!langs[name]) {
28 | throw new Error(`Unsupported lang ${name}`);
29 | }
30 | repl = langs[name];
31 | repl.setREPL();
32 |
33 | const langREPL = repl.getREPL();
34 | if(langREPL.updateCompilerOptions) {
35 | langREPL.updateCompilerOptions();
36 | }
37 |
38 | return langREPL;
39 | }
40 |
41 | const getNamespace = () => {
42 | const langREPL = getREPL();
43 | if(typeof langREPL.getNamespace === 'function') {
44 | return langREPL.getNamespace();
45 | }
46 | return '';
47 | }
48 |
49 | const aliases = {
50 | js: 'js', json: 'js', node: 'js',
51 | coffee: 'coffee', litcoffee: 'coffee', 'coffee.md': 'coffee',
52 | ls: 'ls',
53 | ts: 'ts', tsx: 'ts',
54 | cljs: 'cljs',
55 | };
56 |
57 | const qualifiedNames = {
58 | js: 'javascript', json: 'javascript', node: 'javascript',
59 | coffee: 'x-coffeescript', litcoffee: 'x-coffeescript', 'coffee.md': 'x-coffeescript',
60 | ls: 'x-liveScript',
61 | ts: 'typescript', tsx: 'typescript',
62 | cljs: 'x-clojure'
63 | };
64 |
65 |
66 | export default {
67 | getREPL,
68 | setREPL,
69 | getREPLProvider,
70 | getNamespace,
71 | getLangName: (ext) => aliases[ext],
72 | getLangQualifiedName: (ext) => qualifiedNames[ext],
73 | setLookupPath: (paths) => repls.forEach(repl => repl.setLookupPath && repl.setLookupPath(paths))
74 | };
75 |
--------------------------------------------------------------------------------
/src/languages/ReplLiveScript.js:
--------------------------------------------------------------------------------
1 | import ls from 'livescript';
2 | import path from 'path';
3 | import {EOL} from 'os';
4 | import nodeREPL from 'repl';
5 | import _ from 'lodash';
6 | import child_process from 'child_process';
7 | import vm from 'vm';
8 | import fs from 'fs';
9 |
10 | let nodeLineListener = () => {};
11 | let promptData = '';
12 |
13 | let loadFile = (module, filename) => {
14 | let result = ls.compile(fs.readFileSync(fileName).toString(), { bare: false });
15 | return module._compile(result.toString(), filename);
16 | };
17 |
18 | // register extensions
19 | let register = () => {
20 | if (require.extensions) {
21 | require.extensions['.ls'] = loadFile;
22 | }
23 |
24 | let fork = child_process.fork;
25 | let binary = require.resolve(path.join(__dirname, '../node_modules/livescript/bin/lsc'));
26 | child_process.fork = (path, args, options) => {
27 | if(/\.ls?$/.test(path)) {
28 | if(!Array.isArray(args)) {
29 | options = args || {};
30 | args = [];
31 | }
32 | args = [path].concat(args);
33 | path = binary;
34 | }
35 | return fork(path, args, options);
36 | };
37 | };
38 |
39 | let evaluate = (input, context, filename, cb) => {
40 | try {
41 | let js = ls.compile(input, { bare: true }).toString();
42 | return cb(null, vm.runInContext(js, context, filename));
43 | } catch(e) {
44 | return cb(e);
45 | }
46 | }
47 |
48 | let transpile = (input, context, cb) => {
49 | try {
50 | let js = ls.compile(input, { bare: true }).toString();
51 | let lines = js.split(/\r?\n/g);
52 | lines.shift();
53 | return cb(null, lines.join(EOL));
54 | } catch(e) {
55 | return cb(e);
56 | }
57 | };
58 |
59 | let addMultilineHandler = ({rli}) => {
60 | nodeLineListener = rli.listeners('line')[0];
61 | rli.removeListener('line', nodeLineListener);
62 | rli.on('line', (cmd) => {
63 | promptData += cmd + EOL;
64 | });
65 | };
66 |
67 | let loadAction = {
68 | help: '?',
69 | action: function(file) {
70 | try {
71 | let stats = fs.statSync(file);
72 | if (stats && stats.isFile()) {
73 | let self = this;
74 | let data = fs.readFileSync(file, 'utf8');
75 | this.displayPrompt();
76 | nodeLineListener(data);
77 | promptData = '';
78 | } else {
79 | this.outputStream.write('Failed to load:' + file + ' is not a file\n');
80 | }
81 | } catch (e) {
82 | this.outputStream.write('Failed to load:' + file + '\n');
83 | }
84 | this.displayPrompt();
85 | }
86 | };
87 |
88 | /// export repl
89 | export default {
90 | start: (options = {}) => {
91 | register();
92 | let opts = _.extend({eval: evaluate}, options);
93 | let repl = nodeREPL.start(opts);
94 | repl.on('exit', () => {
95 | if(!repl.rli.closed) {
96 | repl.outputStream.write(EOL);
97 | }
98 | });
99 | repl.input.on('data', (d) => {
100 | if(d === EOL) {
101 | nodeLineListener(promptData);
102 | promptData = '';
103 | }
104 | });
105 | addMultilineHandler(repl);
106 | repl.transpile = transpile;
107 | repl.defineCommand('load', loadAction);
108 | return repl;
109 | }
110 | };
111 |
--------------------------------------------------------------------------------
/src/stores/ReplActiveInputStore.js:
--------------------------------------------------------------------------------
1 | import ReplActiveInputActions from '../actions/ReplActiveInputActions';
2 | import Reflux from 'reflux';
3 |
4 | let activeSuggestion = null;
5 | let now = false;
6 | let breakPrompt = false;
7 | let format = false;
8 | let autoComplete = false;
9 | let stagedCommands = [];
10 |
11 | const ReplActiveInputStore = Reflux.createStore({
12 | init() {
13 | this.listenToMany(ReplActiveInputActions);
14 | },
15 | onTabCompleteSuggestion(suggestion, id) {
16 | activeSuggestion = { suggestion, id };
17 | now = breakPrompt = format = autoComplete = false;
18 | this.trigger();
19 | },
20 | onResetTabCompleteSuggestion() {
21 | activeSuggestion = null;
22 | now = breakPrompt = format = autoComplete = false;
23 | this.trigger();
24 | },
25 | onPerformAutoComplete() {
26 | autoComplete = true;
27 | this.trigger();
28 | },
29 | onFillTabCompleteSuggestion(suggestion, id) {
30 | activeSuggestion = { suggestion, id };
31 | breakPrompt = format = autoComplete = false;
32 | now = true;
33 | this.trigger();
34 | },
35 | onBreakPrompt() {
36 | activeSuggestion = null;
37 | now = format = autoComplete = false;
38 | breakPrompt = true;
39 | this.trigger();
40 | },
41 | onFormatCode() {
42 | format = true;
43 | autoComplete = false;
44 | this.trigger();
45 | },
46 | onPlayCommands(commands) {
47 | stagedCommands = commands;
48 | this.trigger();
49 | },
50 | tailStagedCommands() {
51 | stagedCommands.shift();
52 | },
53 | onSetTheme(t) {
54 | this.trigger({name: 'theme', value: t});
55 | },
56 | onSetMode(m) {
57 | this.trigger({name: 'mode', value: m});
58 | },
59 | onUpdateSuggestionDelay() {
60 | this.trigger();
61 | },
62 | onSetEditorOption(action) {
63 | this.trigger(action);
64 | },
65 | onUndo() {
66 | this.trigger({action: 'undo'});
67 | },
68 | onRedo() {
69 | this.trigger({action: 'redo'});
70 | },
71 | onSelectAll() {
72 | this.trigger({action: 'selectAll'});
73 | },
74 | onFocus() {
75 | if(global.Mancy.session.editor === 'REPL') {
76 | this.trigger({action: 'focus'});
77 | }
78 | },
79 | getStore() {
80 | return {
81 | activeSuggestion,
82 | now,
83 | breakPrompt,
84 | format,
85 | stagedCommands,
86 | autoComplete,
87 | }
88 | }
89 | });
90 | export default ReplActiveInputStore;
91 |
--------------------------------------------------------------------------------
/src/stores/ReplConsoleStore.js:
--------------------------------------------------------------------------------
1 | import ReplConsoleActions from '../actions/ReplConsoleActions';
2 | import Reflux from 'reflux';
3 | import _ from 'lodash';
4 |
5 | let cache = [];
6 | const ReplConsoleStore = Reflux.createStore({
7 | init() {
8 | this.listenToMany(ReplConsoleActions);
9 | },
10 | onAddEntry(item) {
11 | let dup = false;
12 | if(cache.length) {
13 | let lastItem = cache[cache.length - 1];
14 | item.time = lastItem.time;
15 | item.count = lastItem.count;
16 | if(_.isEqual(item, lastItem)) {
17 | lastItem.count = lastItem.count + 1;
18 | dup = true;
19 | }
20 | }
21 |
22 | if(!dup){
23 | item.count = 1;
24 | item.time = Math.random();
25 | cache.push(item);
26 | }
27 | this.trigger();
28 | },
29 | onClear() {
30 | this.clear();
31 | },
32 | clear() {
33 | cache = [];
34 | this.trigger();
35 | },
36 | getStore() {
37 | return {
38 | entries: cache
39 | }
40 | }
41 | });
42 | export default ReplConsoleStore;
43 |
--------------------------------------------------------------------------------
/src/stores/ReplStatusBarStore.js:
--------------------------------------------------------------------------------
1 | import ReplStatusBarActions from '../actions/ReplStatusBarActions';
2 | import Reflux from 'reflux';
3 |
4 | let newRelease = null;
5 | let language = '';
6 | let mode = '';
7 | let cursor = [1, 1];
8 | const ReplStatusBarStore = Reflux.createStore({
9 | init() {
10 | this.listenToMany(ReplStatusBarActions);
11 | },
12 | onUpdateRunCommand() {
13 | this.trigger();
14 | },
15 | onNewRelease(release) {
16 | newRelease = release;
17 | this.trigger();
18 | },
19 | onUpdateLanguage(lang) {
20 | language = lang;
21 | this.trigger();
22 | },
23 | onUpdateMode(m) {
24 | mode = m.toLowerCase();
25 | this.trigger();
26 | },
27 | onRefresh() {
28 | this.trigger();
29 | },
30 | onCursorActivity(c) {
31 | cursor = c;
32 | this.trigger();
33 | },
34 | getStore() {
35 | let {toggleShiftEnter, lang} = global.Mancy.preferences;
36 | return {
37 | runCommand: toggleShiftEnter,
38 | newRelease,
39 | lang: language || lang,
40 | mode,
41 | cursor
42 | };
43 | }
44 | });
45 | export default ReplStatusBarStore;
46 |
--------------------------------------------------------------------------------
/src/stores/ReplSuggestionStore.js:
--------------------------------------------------------------------------------
1 | import ReplSuggestionActions from '../actions/ReplSuggestionActions';
2 | import Reflux from 'reflux';
3 |
4 | const ReplSuggestionStore = Reflux.createStore({
5 | init() {
6 | this.listenToMany(ReplSuggestionActions);
7 | },
8 | onAddSuggestion(item) {
9 | this.trigger(item);
10 | },
11 | onRemoveSuggestion() {
12 | this.trigger({suggestions:[], input: ''});
13 | }
14 | });
15 | export default ReplSuggestionStore;
16 |
--------------------------------------------------------------------------------
/stylesheets/clojurescript/repl-output-cljs-docs.scss:
--------------------------------------------------------------------------------
1 | @import '../themes';
2 | @import '../repl-common';
3 |
4 | @mixin replOutputCljsDocs($theme) {
5 |
6 | .repl-cljs-docs-fold {
7 | flex: 1;
8 | .repl-cljs-doc-list {
9 | .title { padding-left: 6px; }
10 | }
11 | .repl-cljs-doc {
12 | padding-left: 12px;
13 | .doc-header {
14 | padding-left: 6px;
15 | font-weight: 900;
16 | color:if($theme == $dark-theme, $dark-app-cljs-doc-header-color, $lt-app-cljs-doc-header-color);
17 | }
18 | .doc-body {
19 | .doc-definition {
20 |
21 | }
22 | .doc-description {
23 | padding-top: 6px;
24 | padding-bottom: 6px;
25 | color: if($theme == $dark-theme, $dark-app-cljs-doc-desc-color, $lt-app-cljs-doc-desc-color);
26 | }
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/stylesheets/clojurescript/repl-output-cljs-meta.scss:
--------------------------------------------------------------------------------
1 | @import '../themes';
2 | @import '../repl-common';
3 |
4 | @mixin replOutputCljsMeta($theme) {
5 |
6 | .repl-cljs-meta-fold {
7 | flex: 1;
8 | padding-left: 12px;
9 | .repl-cljs-meta {
10 | word-break: break-all;
11 | .fa-minus-square-o, .fa-plus-square-o {
12 | color: if($theme == $dark-theme, $dark-app-entry-message-output-arr-fold-color, $lt-app-entry-message-output-arr-fold-color);
13 | padding-right: 6px;
14 | position: relative;
15 | top: 1px;
16 | }
17 | .meta-label {
18 | padding-left: 5px;
19 | }
20 | .meta-records {
21 | padding-left: 15px;
22 | .meta-record {
23 | .meta-key {
24 | padding-right: 12px;
25 | }
26 | .meta-value {
27 |
28 | }
29 | }
30 | }
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/stylesheets/clojurescript/repl-output-cljs-source.scss:
--------------------------------------------------------------------------------
1 | @import '../themes';
2 | @import '../repl-common';
3 |
4 | @mixin replOutputCljsSource($theme) {
5 |
6 | .repl-cljs-source-fold {
7 | flex: 1;
8 | .repl-cljs-source {
9 | word-break: break-all;
10 | .fa { padding-right: 6px; }
11 | .repl-cljs-source-code {
12 |
13 | }
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/stylesheets/clojurescript/repl-output-cljs-val.scss:
--------------------------------------------------------------------------------
1 | @import '../themes';
2 | @import '../repl-common';
3 |
4 | @mixin replOutputCljsVal($theme) {
5 |
6 | .repl-cljs-val {
7 | flex: 1;
8 | display: inline-flex;
9 | flex-direction: row;
10 |
11 | .prefix {
12 | padding-right: 6px;
13 | }
14 |
15 | .suffix {
16 | padding-left: 6px;
17 | }
18 |
19 | .value {
20 | font-weight: 900;
21 | }
22 |
23 | .tag {
24 | background-color: if($theme == $dark-theme, $dark-app-tag-bg-color, $lt-app-tag-bg-color);
25 | color: if($theme == $dark-theme, $dark-app-tag-color, $lt-app-tag-color);
26 | border-radius: 4px;
27 | padding-left: 5px;
28 | padding-right: 5px;
29 | padding-top: 1px;
30 | padding-bottom: 1px;
31 | font-size: 0.75em;
32 | height: 80%;
33 | position: relative;
34 | top: 3px;
35 | font-weight: 900;
36 | margin-left: 6px;
37 | cursor: default;
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/stylesheets/clojurescript/repl-output-cljs-var.scss:
--------------------------------------------------------------------------------
1 | @import '../themes';
2 | @import '../repl-common';
3 |
4 | @mixin replOutputCljsVar($theme) {
5 |
6 | .repl-cljs-var-fold {
7 | flex: 1;
8 | .repl-cljs-var {
9 | word-break: break-all;
10 | .fa-play {
11 | font-size: 0.8em;
12 | color: if($theme == $dark-theme, $dark-app-entry-message-output-arr-fold-color, $lt-app-entry-message-output-arr-fold-color);
13 | padding-right: 3px;
14 | }
15 | .fa-play.fa-rotate-90 {
16 | position: relative;
17 | top: 2px;
18 | padding-top: 5px;
19 | padding-right: 3px;
20 | }
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/stylesheets/clojurescript/repl-output-cljs-wrapper.scss:
--------------------------------------------------------------------------------
1 | @import '../themes';
2 | @import '../repl-common';
3 |
4 | @mixin replOutputCljsWrapper($theme) {
5 |
6 | .repl-cljs-wrapper {
7 | flex: 1;
8 | flex-direction: column;
9 |
10 | .repl-cljs-annotate {
11 | .fa {
12 | padding-right: 6px;
13 | color: if($theme == $dark-theme, $dark-app-entry-message-output-arr-fold-color, $lt-app-entry-message-output-arr-fold-color);
14 | }
15 | }
16 | .repl-cljs-grid-annotate, .repl-cljs-chart-annotate {
17 | display: flex;
18 | padding-left: 12px;
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/stylesheets/configs.scss:
--------------------------------------------------------------------------------
1 | $app-font-family: 'Droid Sans Mono',sans-serif;
2 | $app-font-size: 11pt;
3 | $app-text-selection-color: whitesmoke;
4 | $app-text-selection-background-color: #B964C7;
5 | $app-text-error-color: tomato;
6 | $app-external-icon-color: #EC348F;
7 | $app-external-link-color: #97AD5A;
8 |
9 | $app-green-execution-color: #25A725;
10 | $app-red-execution-color: red;
11 | $app-orange-execution-color: orange;
12 |
13 | $dark-theme: 'dark-theme';
14 | $light-theme: 'light-theme';
15 |
--------------------------------------------------------------------------------
/stylesheets/highlight.scss:
--------------------------------------------------------------------------------
1 | @mixin stackTraceHighlight($theme) {
2 | .stack-error-at {
3 | color: if($theme == $dark-theme, $dark-app-stack-error-at-color, $lt-app-stack-error-at-color);
4 | }
5 | .stack-error-function {
6 | color: if($theme == $dark-theme, $dark-app-stack-error-function-color, $lt-app-stack-error-function-color);
7 | }
8 |
9 | .stack-error-file {
10 | color: if($theme == $dark-theme, $dark-app-stack-error-file-color, $lt-app-stack-error-file-color);
11 | }
12 |
13 | .stack-error-row {
14 | color: if($theme == $dark-theme, $dark-app-stack-error-row-color, $lt-app-stack-error-row-color);
15 | }
16 | .stack-error-column {
17 | color: if($theme == $dark-theme, $dark-app-stack-error-column-color, $lt-app-stack-error-column-color);
18 | }
19 |
20 | .error-name {
21 | color: if($theme == $dark-theme, $dark-app-stack-error-name-color, $lt-app-stack-error-name-color);
22 | }
23 |
24 | .error-description {
25 | color: if($theme == $dark-theme, $dark-app-stack-error-description-color, $lt-app-stack-error-description-color);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/stylesheets/repl-common.scss:
--------------------------------------------------------------------------------
1 | @import 'themes';
2 |
3 |
4 | // google font
5 | @font-face {
6 | font-family: 'Josefin Sans';
7 | font-style: normal;
8 | font-weight: 400;
9 | src: url('../fonts/Josefin_Sans/JosefinSans-Regular.ttf');
10 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
11 | }
12 |
13 | @font-face {
14 | font-family: 'Droid Sans Mono';
15 | font-style: normal;
16 | font-weight: 400;
17 | src: url('../fonts/Droid_Sans_Mono/DroidSansMono.ttf');
18 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
19 | }
20 |
21 | @font-face {
22 | font-family: 'FiraCode';
23 | font-style: normal;
24 | font-weight: 400;
25 | src: url('../fonts/FiraCode/FiraCode-Regular.otf');
26 | }
27 |
28 | @mixin fullHeight() {
29 | height: calc(100vh - (#{$app-font-size} + 20px));
30 | }
31 |
32 | @mixin notSelectable() {
33 | -webkit-user-select: none;
34 | user-select: none;
35 | }
36 |
37 | @mixin selectable() {
38 | -webkit-user-select: initial;
39 | user-select: initial;
40 | }
41 |
42 | @mixin entryLayout() {
43 | flex: 1;
44 | min-height: $app-font-size;
45 | padding-left: 10px;
46 | margin: 0px;
47 | }
48 |
49 | @mixin arrowIcon() {
50 | width: 10px;
51 | text-align: center;
52 | }
53 |
54 | @mixin editor() {
55 | outline: none;
56 | margin: 0;
57 | word-wrap: break-word;
58 | word-break: break-word;
59 | white-space: pre-wrap;
60 | }
61 |
62 | .dull {
63 | opacity: 0.7;
64 | }
65 |
66 | .close {
67 | color: $app-text-error-color;
68 | }
69 |
70 | .flex {
71 | flex: 1;
72 | }
73 |
74 | button {
75 | margin-right: 5px;
76 | }
77 |
78 | .read-error {
79 | color: $app-text-error-color;
80 | }
81 |
82 | small {
83 | font-size: 8px;
84 | }
85 |
86 | [disabled="true"] {
87 | cursor: not-allowed !important;
88 | }
89 |
--------------------------------------------------------------------------------
/stylesheets/repl-console-environment-watcher.scss:
--------------------------------------------------------------------------------
1 | @import 'themes';
2 | @import 'repl-common';
3 | @import 'repl-output';
4 | @import 'repl-source-file';
5 |
6 | @mixin replConsoleEnvironment($theme) {
7 | .repl-console-environment {
8 | flex: 0 0 200px;
9 | display: flex;
10 | flex-direction: column;
11 | }
12 | .repl-console-environment-head {
13 | @include notSelectable();
14 | width: 100%;
15 | height: 30px;
16 | min-height: 30px;
17 | border-bottom: 1px solid if($theme == $dark-theme, $dark-app-console-message-filter-border-color, $lt-app-console-message-filter-border-color);
18 | font-weight: 900;
19 | font-size: 110%;
20 | display: flex;
21 | align-self: center;
22 |
23 | .repl-console-environment-title {
24 | text-align: center;
25 | align-self: center;
26 | }
27 | }
28 | .repl-console-environment-body {
29 | flex: 1;
30 | overflow: auto;
31 | padding-right: 10px;
32 | .repl-console-environment-body-header {
33 | @include notSelectable();
34 | font-weight: 900;
35 | display: flex;
36 | width: 100%;
37 | height: 30px;
38 | padding: 0px 5px;
39 | margin-bottom: 10px;
40 | background-color: if($theme == $dark-theme, $dark-app-console-env-data-heading-color, $lt-app-console-env-data-heading-color);
41 | .repl-console-environment-listing-title {
42 | align-self: center;
43 | }
44 | }
45 |
46 | .repl-console-environment-listing {
47 | @include replOutput($theme);
48 | margin: 0 5px;
49 | .env-entry {
50 | display: flex;
51 | padding: 5px 0px;
52 | .env-key, .env-value {
53 | flex: 1;
54 | }
55 | }
56 | }
57 |
58 | .repl-console-environment-no-data {
59 | @include notSelectable();
60 | margin-bottom: 10px;
61 | text-align: center;
62 | color: if($theme == $dark-theme, $dark-app-console-env-no-data-color, $lt-app-console-env-no-data-color);
63 | }
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/stylesheets/repl-container-left.scss:
--------------------------------------------------------------------------------
1 | @import 'themes';
2 | @import 'repl-common';
3 | @import 'repl-prompt';
4 | @import 'repl-entries';
5 |
6 |
7 | @mixin containerLeft($theme) {
8 | .repl-container-left {
9 | flex: 1;
10 | display: flex;
11 | @include fullHeight();
12 | overflow: auto;
13 | flex-direction: column;
14 |
15 | .repl-header {
16 | height: 5px;
17 | }
18 |
19 | @include replEntries($theme);
20 | @include replPrompt($theme);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/stylesheets/repl-container-right.scss:
--------------------------------------------------------------------------------
1 | @import 'themes';
2 | @import 'repl-common';
3 | @import 'repl-console-message';
4 |
5 | @mixin containerRight($theme) {
6 | .repl-container-right {
7 | display: flex;
8 | max-width: 100vw;
9 | flex: 0 0 30vw;
10 | min-width: 8px;
11 | @include fullHeight();
12 | overflow: auto;
13 | flex-direction: column;
14 |
15 | .repl-header {
16 | height: 5px;
17 | }
18 |
19 | .repl-console {
20 | min-width: 280px;
21 | position: relative;
22 | top: 0;
23 | background-color: if($theme == $dark-theme, $dark-app-console-background-color, $lt-app-console-background-color);
24 | color: if($theme == $dark-theme, $dark-app-console-color, $lt-app-console-color);
25 | overflow: auto;
26 | flex: 1;
27 | display: flex;
28 | border-top-left-radius: 5px;
29 | border-bottom-left-radius: 5px;
30 |
31 | .repl-console-resizeable {
32 | display: flex;
33 | width: 8px;
34 | position: relative;
35 | @include fullHeight();
36 | background-color: if($theme == $dark-theme, $dark-app-console-resize-handle-color, $lt-app-console-resize-handle-color);
37 | border-top-left-radius: 5px;
38 | border-bottom-left-radius: 5px;
39 | cursor: ew-resize;
40 | align-items: center;
41 |
42 | .repl-console-drag-lines {
43 | @include notSelectable();
44 |
45 | &:before {
46 | content: 'ǁ';
47 | text-align: center;
48 | margin: 1px;
49 | color: if($theme == $dark-theme, $dark-app-console-drag-lines-color, $lt-app-console-drag-lines-color);
50 | }
51 | }
52 | }
53 | @include replConsoleMessage($theme);
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/stylesheets/repl-entries.scss:
--------------------------------------------------------------------------------
1 | @import 'themes';
2 | @import 'repl-common';
3 | @import 'repl-entry-status';
4 | @import 'repl-entry-message';
5 |
6 | @mixin replEntries($theme) {
7 | .repl-entries {
8 | .repl-entry {
9 | display: flex;
10 | margin: 0;
11 | padding: 5px;
12 | &.repl-notebook {
13 | padding: 0px;
14 | }
15 | .repl-entry-icon,
16 | .repl-entry-status {
17 | @include notSelectable();
18 | }
19 |
20 | .repl-entry-icon {
21 | color: if($theme == $dark-theme, $dark-app-entry-icon-color, $lt-app-entry-icon-color);
22 | @include arrowIcon();
23 | .fa {
24 | cursor: pointer;
25 | }
26 | }
27 |
28 | @include replEntryStatus($theme);
29 | @include replEntryMessage($theme);
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/stylesheets/repl-entry-message.scss:
--------------------------------------------------------------------------------
1 | @import 'themes';
2 | @import 'repl-common';
3 | @import 'highlight';
4 | @import 'repl-output';
5 | @import 'repl-source-file';
6 |
7 | @mixin replEntryMessage($theme) {
8 | .repl-entry-message {
9 | @include entryLayout();
10 |
11 | &.repl-notebook {
12 | padding: 0px;
13 | .repl-entry-message-output {
14 | padding: 5px 25px 5px 25px;
15 | }
16 | }
17 | .repl-entry-command-container {
18 | display: flex;
19 | .tag {
20 | background-color: if($theme == $dark-theme, $dark-app-tag-bg-color, $lt-app-tag-bg-color);
21 | color: if($theme == $dark-theme, $dark-app-tag-color, $lt-app-tag-color);
22 | border-radius: 4px;
23 | padding-left: 5px;
24 | padding-right: 5px;
25 | padding-top: 1px;
26 | padding-bottom: 1px;
27 | font-size: 0.75em;
28 | height: 80%;
29 | position: relative;
30 | top: 3px;
31 | font-weight: 900;
32 | margin-left: 6px;
33 | cursor: default;
34 | }
35 |
36 | .execution-time {
37 | position: relative;
38 | top: 3px;
39 | &.green {
40 | color: $app-green-execution-color;
41 | }
42 | &.red {
43 | color: $app-red-execution-color;
44 | }
45 | &.orange {
46 | color: $app-orange-execution-color;
47 | }
48 | }
49 |
50 | .repl-entry-message-command {
51 | flex: 1;
52 | min-height: $app-font-size;
53 | word-wrap: break-word;
54 | word-break: break-word;
55 | white-space: pre-wrap;
56 | }
57 |
58 | .ellipsis {
59 | &:after {
60 | content: '\2026';
61 | color: if($theme == $dark-theme, $dark-app-entry-ellipsis-color, $lt-app-entry-ellipsis-color);
62 | }
63 | }
64 | }
65 |
66 | .repl-entry-message-output {
67 | word-wrap: break-word;
68 | word-break: break-word;
69 | white-space: pre-wrap;
70 | padding: 5px 0;
71 | position: relative;
72 | cursor: default;
73 |
74 | @include replSourceFile($theme);
75 |
76 | .fa-clone {
77 | @include notSelectable();
78 | position: absolute;
79 | color: if($theme == $dark-theme, $dark-app-entry-icon-copy-color, $lt-app-entry-icon-copy-color);
80 | font-size: 0.7em;
81 | position: relative;
82 | font-weight: 900;
83 | left: -10px;
84 | padding-top: 4px;
85 | top: 0;
86 | cursor: pointer;
87 |
88 | &:active {
89 | top: 3px;
90 | }
91 | }
92 |
93 | .repl-entry-message-output-function {
94 | .fa {
95 | padding-right: 10px;
96 | padding-top: 4px;
97 | color: if($theme == $dark-theme, $dark-app-entry-message-output-expand-collapse-color, $lt-app-entry-message-output-expand-collapse-color);
98 | }
99 | .fa-minus-square-o ~ img ~ span {
100 | display: block;
101 | }
102 | .es-img {
103 | padding-right: 5px;
104 | height: 1em;
105 | width: 1em;
106 | }
107 | }
108 |
109 | @include replOutput($theme);
110 | .repl-entry-output-error {
111 | .repl-entry-output-error-message {
112 | .fa-play {
113 | padding-right: 2px;
114 | color: if($theme == $dark-theme, $dark-app-entry-message-output-arr-fold-color, $lt-app-entry-message-output-arr-fold-color);
115 | }
116 | .repl-entry-output-error-message-heading {
117 | padding-left: 5px;
118 | }
119 | .syntax-error {
120 | .repl-entry-output-error-message-heading {
121 | padding-left: 0px;
122 | }
123 | .err-underline {
124 | text-decoration: underline;
125 | text-decoration-color: $app-text-error-color;
126 | font-size: 0.9em;
127 | }
128 | }
129 | .repl-entry-output-error-stack {
130 | .repl-entry-output-error-stack-lines {
131 | padding-left: calc(1em + 5px);
132 | }
133 | }
134 | }
135 |
136 | @include stackTraceHighlight($theme);
137 | }
138 |
139 | .promise-object {
140 | .promise-status, .promise-value {
141 | color: if($theme == $dark-theme, $dark-app-entry-message-output-primitive-color, $lt-app-entry-message-output-primitive-color);
142 | }
143 | }
144 |
145 | .primitive-object {
146 | .primitive-key {
147 | color: if($theme == $dark-theme, $dark-app-entry-message-output-primitive-color, $lt-app-entry-message-output-primitive-color);
148 | }
149 | }
150 | }
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/stylesheets/repl-entry-status.scss:
--------------------------------------------------------------------------------
1 | @import 'themes';
2 | @import 'repl-common';
3 |
4 | @mixin replEntryStatus($theme) {
5 | .repl-entry-status {
6 | padding-right: 8px;
7 |
8 | .repeat,
9 | .error,
10 | .plus,
11 | .minus,
12 | .remove {
13 | padding-left: 6px;
14 | cursor: pointer;
15 | }
16 |
17 | .repeat {
18 | color: if($theme == $dark-theme, $dark-app-entry-status-redo-color, $lt-app-entry-status-redo-color);
19 | }
20 |
21 | .error {
22 | color: if($theme == $dark-theme, $dark-app-entry-status-error-color, $lt-app-entry-status-error-color);
23 | }
24 |
25 | .minus {
26 | color: if($theme == $dark-theme, $dark-app-entry-status-minus-color, $lt-app-entry-status-minus-color);
27 | }
28 |
29 | .plus {
30 | color: if($theme == $dark-theme, $dark-app-entry-status-plus-color, $lt-app-entry-status-plus-color);
31 | }
32 |
33 | .remove {
34 | color: if($theme == $dark-theme, $dark-app-entry-status-remove-color, $lt-app-entry-status-remove-color);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/stylesheets/repl-output-array.scss:
--------------------------------------------------------------------------------
1 | @import 'themes';
2 | @import 'repl-common';
3 |
4 | @mixin replOutputArrayFold($theme) {
5 | .repl-entry-message-output-array-folds {
6 | .repl-entry-message-output-array {
7 | .fa-play {
8 | font-size: 0.8em;
9 | color: if($theme == $dark-theme, $dark-app-entry-message-output-arr-fold-color, $lt-app-entry-message-output-arr-fold-color);
10 | }
11 | .fa-hashtag {
12 | padding-left: 5px;
13 | font-size: 70%;
14 | cursor: pointer;
15 | color: if($theme == $dark-theme, $dark-app-entry-message-output-bind-color, $lt-app-entry-message-output-bind-color);
16 | }
17 |
18 | .cljs-tag {
19 | background-color: if($theme == $dark-theme, $dark-app-tag-bg-color, $lt-app-tag-bg-color);
20 | color: if($theme == $dark-theme, $dark-app-tag-color, $lt-app-tag-color);
21 | border-radius: 4px;
22 | padding-left: 5px;
23 | padding-right: 5px;
24 | padding-top: 1px;
25 | padding-bottom: 1px;
26 | font-size: 0.8em;
27 | height: 80%;
28 | font-weight: 900;
29 | margin-left: 6px;
30 | cursor: default;
31 | }
32 |
33 | .array-desc {
34 | padding-left: 5px;
35 | .ellipsis {
36 | padding-left: 5px;
37 | }
38 | }
39 |
40 | .array-rec {
41 | display: flex;
42 | flex-direction: column;
43 | &.inline {
44 | display: inline-flex;
45 | flex-direction: row;
46 | .array-entry {
47 | padding-left: 5px;
48 | padding-right: 5px;
49 | }
50 | }
51 | .array-entry {
52 | display: flex;
53 | padding-left: 10px;
54 | .map-key {
55 | padding-right: 12px;
56 | }
57 | .array-idx {
58 | color: if($theme == $dark-theme, $dark-app-entry-message-output-arr-idx-color, $lt-app-entry-message-output-arr-idx-color);
59 | }
60 | }
61 | }
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/stylesheets/repl-output-buffer-explorer.scss:
--------------------------------------------------------------------------------
1 | @import 'themes';
2 | @import 'repl-common';
3 |
4 | @mixin bufferRecord($theme){
5 | padding: 3px 0px;
6 | .offset {
7 | font-weight: 900;
8 | padding: 0px 10px;
9 | width: 60px;
10 | text-align: right;
11 | display: inline-block;
12 | }
13 |
14 | .offset-pos, .offset-ascii-pos {
15 | padding: 0px 5px;
16 | text-align: center;
17 | &:nth-child(8n + 1) {
18 | margin-right: 15px;
19 | }
20 | }
21 |
22 | .offset-ascii-pos {
23 | padding: 0px;
24 | }
25 | .offset-pos.even.in {
26 | background-color: if($theme == $dark-theme, $dark-app-data-buffer-even-in-color, $lt-app-data-buffer-even-in-color);
27 | }
28 |
29 | .offset-ascii-pos.even.in {
30 | background-color: if($theme == $dark-theme, $dark-app-data-buffer-even-in-ascii-color, $lt-app-data-buffer-even-in-ascii-color);
31 | }
32 |
33 | .offset-pos.odd.in {
34 | background-color: if($theme == $dark-theme, $dark-app-data-buffer-odd-in-color, $lt-app-data-buffer-odd-in-color);
35 | }
36 |
37 | .offset-ascii-pos.odd.in {
38 | background-color: if($theme == $dark-theme, $dark-app-data-buffer-odd-in-ascii-color, $lt-app-data-buffer-odd-in-ascii-color);
39 | }
40 |
41 | .out {
42 | background-color: if($theme == $dark-theme, $dark-app-data-buffer-out-bg-color, $lt-app-data-buffer-out-bg-color);;
43 | }
44 |
45 | .offset-ascii-pos.mask.in {
46 | color: if($theme == $dark-theme, $dark-app-data-buffer-mask-color, $lt-app-data-buffer-mask-color);
47 | }
48 | }
49 |
50 | @mixin replOutputBufferExplorer($theme) {
51 |
52 | .repl-output-buffer-explorer-container {
53 | .data-explorer-label {
54 | color: if($theme == $dark-theme, $dark-app-data-explorer-label-color, $lt-app-data-explorer-label-color);
55 | padding: 0px 0px 0px 5px;
56 | }
57 | }
58 |
59 | .repl-output-data-buffer-explorer {
60 | min-width: 700px;
61 | overflow: auto;
62 | color: if($theme == $dark-theme, $dark-app-data-buffer-explorer-color, $lt-app-data-buffer-explorer-color);
63 | border-radius: 5px;
64 | padding-top: 10px;
65 | border: 1px dashed currentColor;
66 |
67 | .data-buffer-grid-header {
68 | font-weight: 900;
69 | @include bufferRecord($theme);
70 | }
71 |
72 | .data-buffer-grid-body {
73 | .data-buffer-grid-row {
74 | @include bufferRecord($theme);
75 | }
76 | }
77 |
78 | .data-buffer-grid-pagination {
79 | display: flex;
80 | align-items: center;
81 |
82 | i.fa {
83 | font-size: 2em;
84 | padding: 3px 5px;
85 | cursor: pointer;
86 | }
87 |
88 | .fa-caret-right {
89 | text-align: left;
90 | }
91 | .fa-caret-left {
92 | text-align: right;
93 | }
94 | .fa-caret-left.disabled, .fa-caret-right.disabled {
95 | pointer-events: none;
96 | opacity: 0.5;
97 | }
98 |
99 | .placeholder {
100 | flex: 1;
101 | }
102 |
103 | .textbox {
104 | padding: 0px 4px;
105 | input {
106 | height: 0.9em;
107 | outline: none;
108 | }
109 | }
110 | }
111 | }
112 |
113 | }
114 |
--------------------------------------------------------------------------------
/stylesheets/repl-output-chart-viewer.scss:
--------------------------------------------------------------------------------
1 | @import 'themes';
2 | @import 'repl-common';
3 |
4 | @mixin replOutputChartViewer($theme) {
5 | .repl-output-chart-viewer-container {
6 | flex: 1;
7 | .data-explorer-label {
8 | color: if($theme == $dark-theme, $dark-app-data-explorer-label-color, $lt-app-data-explorer-label-color);
9 | padding: 0px 0px 0px 5px;
10 | }
11 |
12 | .repl-output-data-chart-viewer {
13 | .chart-viewer {
14 | display: block;
15 | position: relative;
16 | top: 0px;
17 | left: 0px;
18 |
19 | .c3 line, .c3 path {
20 | stroke: if($theme == $dark-theme, $dark-app-chart-stroke-color, $lt-app-chart-stroke-color);
21 | }
22 | g {
23 | fill: if($theme == $dark-theme, $dark-app-chart-text-color, $lt-app-chart-text-color);
24 | }
25 | .c3-tooltip-container {
26 | color: if($theme == $dark-theme, $dark-app-chart-text-color, $lt-app-color);
27 | }
28 | }
29 | .chart-viewer-preferences {
30 | display: flex;
31 | margin: auto;
32 | align-items: center;
33 | .fa {
34 | color: if($theme == $dark-theme, $dark-app-chart-icon-color, $lt-app-chart-icon-color);
35 | padding: 0px 5px;
36 | cursor: pointer;
37 | }
38 | .placeholder {
39 | flex: 1;
40 | }
41 | .fa.selected {
42 | pointer-events: none;
43 | color: if($theme == $dark-theme, $dark-app-chart-icon-selected-color, $lt-app-chart-icon-selected-color);
44 | }
45 |
46 | .checkbox-group {
47 | padding: 0px 5px;
48 | }
49 | }
50 | }
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/stylesheets/repl-output-color.scss:
--------------------------------------------------------------------------------
1 | @import 'themes';
2 | @import 'repl-common';
3 |
4 | @mixin replOutputColor($theme) {
5 |
6 | .repl-color {
7 | .repl-color-box {
8 | width: 1em;
9 | height: 1em;
10 | border-radius: 3px;
11 | display: inline-flex;
12 | align-self: center;
13 | position: relative;
14 | top: 2px;
15 | margin-left: 5px;
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/stylesheets/repl-output-crypto.scss:
--------------------------------------------------------------------------------
1 | @import 'themes';
2 | @import 'repl-common';
3 |
4 | @mixin replOutputCrypto($theme) {
5 | .repl-output-crypto.extend{
6 | flex: 1;
7 | }
8 | .repl-output-crypto{
9 | .repl-crypto-data {
10 | display: inline-flex;
11 | .fa-lock, .fa-unlock {
12 | padding-left: 5px;
13 | cursor: pointer;
14 | top: 3px;
15 | position: relative;
16 | }
17 | .fa-lock {
18 | color: if($theme == $dark-theme, $dark-app-crypto-lock-color, $lt-app-crypto-lock-color);
19 | display: flex;
20 | align-self: center;
21 | top: 0px;
22 | }
23 | .fa-unlock {
24 | color: if($theme == $dark-theme, $dark-app-crypto-unlock-color, $lt-app-crypto-unlock-color);
25 | }
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/stylesheets/repl-output-grid-viewer.scss:
--------------------------------------------------------------------------------
1 | @import 'themes';
2 | @import 'repl-common';
3 |
4 | @mixin replOutputGridViewer($theme) {
5 | .repl-output-grid-viewer-container {
6 | .data-explorer-label {
7 | color: if($theme == $dark-theme, $dark-app-data-explorer-label-color, $lt-app-data-explorer-label-color);
8 | padding: 0px 0px 0px 5px;
9 | }
10 |
11 | .repl-output-grid-viewer {
12 | max-height: 300px;
13 | overflow: auto;
14 | display: flex;
15 |
16 | .grid-viewer {
17 | border-collapse: separate;
18 | border-spacing: 0px;
19 | border-radius: 5px;
20 | margin: 0 auto;
21 | border: 1px solid if($theme == $dark-theme, $dark-app-data-grid-border-color, $lt-app-data-grid-border-color);
22 |
23 | .grid-caption {
24 | min-width: 160px;
25 | padding: 10px;
26 | }
27 | td, th {
28 | text-align: center;
29 | border: 1px solid if($theme == $dark-theme, $dark-app-data-grid-inner-border-color, $lt-app-data-grid-inner-border-color);
30 | border-spacing: 0px;
31 | border-right-style: solid;
32 | border-bottom-style: solid;
33 | border-top-style: none;
34 | border-left-style: none;
35 | padding: 5px;
36 | }
37 | td:last-child, th:last-child {
38 | border-right-style: none;
39 | }
40 | tbody > tr:last-child th, tbody > tr:last-child td{
41 | border-bottom-style: none;
42 | }
43 | th {
44 | color: if($theme == $dark-theme, $dark-app-data-grid-header-color, $lt-app-data-grid-header-color);
45 | }
46 | }
47 | }
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/stylesheets/repl-output-html.scss:
--------------------------------------------------------------------------------
1 | @import 'themes';
2 | @import 'repl-common';
3 |
4 | @mixin replOutputHTML($theme) {
5 |
6 | .repl-html-fold {
7 | flex: 1;
8 |
9 | .fa-html5 {
10 | color: if($theme == $dark-theme, $dark-app-active-html-logo-color, $lt-app-active-html-logo-color);;
11 | padding-left: 5px;
12 | cursor: pointer;
13 | }
14 |
15 | .fa-html5.nohtml {
16 | color: if($theme == $dark-theme, $dark-app-inactive-html-logo-color, $lt-app-inactive-html-logo-color);;
17 | }
18 |
19 |
20 | iframe.sandbox-view {
21 | display: block;
22 | border: none;
23 | width: 100%;
24 | background-color: initial;
25 | overflow: auto;
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/stylesheets/repl-output-integer.scss:
--------------------------------------------------------------------------------
1 | @import 'themes';
2 |
3 | @mixin replOutputInteger($theme) {
4 |
5 | .repl-integer {
6 | .toggle-number {
7 | cursor: pointer;
8 | border-bottom: 1px dotted grey;
9 | border-bottom-right-radius: 2px;
10 | border-bottom-left-radius: 2px;
11 | }
12 | .mode-group {
13 | opacity: 0.5;
14 | margin: 3px 5px;
15 | display: inline-flex;
16 | border: 1px solid if($theme == $dark-theme, $dark-app-integer-mode-color, $lt-app-integer-mode-color);
17 | border-radius: 3px;
18 | .mode {
19 | width: 1.2em;
20 | text-align: center;
21 | border-right: 1px solid if($theme == $dark-theme, $dark-app-integer-mode-color, $lt-app-integer-mode-color);
22 | cursor: pointer;
23 | font-size: 0.8em;
24 |
25 | &:last-child {
26 | border-right: none;
27 | }
28 | }
29 | .mode.selected {
30 | background-color: if($theme == $dark-theme, $dark-app-integer-mode-color, $lt-app-integer-mode-color);
31 | color: white;
32 | }
33 | .mode {
34 | position: relative;
35 | &:before {
36 | content: attr(data-token);
37 | position: absolute;
38 | top: -1.4em;
39 | font-size: 0.7em;
40 | color: if($theme == $dark-theme, $dark-app-integer-mode-title-color, $lt-app-integer-mode-title-color);
41 | }
42 | }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/stylesheets/repl-output-object.scss:
--------------------------------------------------------------------------------
1 | @import 'themes';
2 | @import 'repl-common';
3 |
4 | @mixin replOutputObjectFold($theme) {
5 | .repl-entry-message-output-object-folds {
6 | flex: 1;
7 | .repl-entry-message-output-object {
8 | .fa-play {
9 | font-size: 0.8em;
10 | color: if($theme == $dark-theme, $dark-app-entry-message-output-arr-fold-color, $lt-app-entry-message-output-arr-fold-color);
11 | }
12 | .fa-hashtag {
13 | padding-left: 5px;
14 | font-size: 70%;
15 | cursor: pointer;
16 | color: if($theme == $dark-theme, $dark-app-entry-message-output-bind-color, $lt-app-entry-message-output-bind-color);
17 | }
18 |
19 | .fa-calendar {
20 | padding: 0px 5px;
21 | color: if($theme == $dark-theme, $dark-app-date-icon-color, $lt-app-date-icon-color);
22 | }
23 |
24 | .fa-download {
25 | padding: 0px 5px;
26 | position: relative;
27 | top: 1px;
28 | font-size: 0.8em;
29 | cursor: pointer;
30 | color: if($theme == $dark-theme, $dark-app-download-color, $lt-app-download-color);
31 | }
32 |
33 | .object-desc {
34 | padding-left: 0px;
35 | }
36 |
37 | .object-rec {
38 | display: flex;
39 | flex-direction: column;
40 |
41 | .object-entry {
42 | display: flex;
43 | padding-left: 10px;
44 |
45 | .object-key {
46 | color: if($theme == $dark-theme, $dark-app-entry-message-output-arr-idx-color, $lt-app-entry-message-output-arr-idx-color);
47 | }
48 | }
49 | }
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/stylesheets/repl-output-regex.scss:
--------------------------------------------------------------------------------
1 | @import 'themes';
2 | @import 'repl-common';
3 |
4 | @mixin replOutputRegex($theme) {
5 |
6 | .repl-regex-fold {
7 | flex: 1;
8 | .repl-regex {
9 |
10 | .fa-play {
11 | color: if($theme == $dark-theme, $dark-app-regex-fold-color, $lt-app-regex-fold-color);
12 | font-size: 0.8em;
13 | position: relative;
14 | top: -1px;
15 | left: 0px;
16 | padding-right: 2px;
17 | }
18 | .fa-hashtag {
19 | padding-left: 5px;
20 | font-size: 70%;
21 | cursor: pointer;
22 | color: if($theme == $dark-theme, $dark-app-entry-message-output-bind-color, $lt-app-entry-message-output-bind-color);
23 | }
24 |
25 | .repl-regex-play-ground[contentEditable=true]:empty:not(:focus):before {
26 | content:attr(placeholder);
27 | color: if($theme == $dark-theme, $dark-app-regex-playground-placeholder-color, $lt-app-regex-playground-placeholder-color);
28 | }
29 |
30 | .repl-regex-play-ground {
31 | @include editor();
32 | color: if($theme == $dark-theme, $dark-app-regex-playground-color, $lt-app-regex-playground-color);
33 | margin-top: 5px;
34 | border: 2px solid if($theme == $dark-theme, $dark-app-regex-playground-border-color, $lt-app-regex-playground-border-color);
35 | border-radius: 5px;
36 | padding: 5px;
37 |
38 | .matched {
39 | background-color: if($theme == $dark-theme, $dark-app-pattern-matched-bg-color, $lt-app-pattern-matched-bg-color);
40 | }
41 | }
42 |
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/stylesheets/repl-output-string.scss:
--------------------------------------------------------------------------------
1 | @import 'themes';
2 | @import 'repl-common';
3 |
4 | @mixin replOutputString($theme) {
5 |
6 | .repl-string-fold {
7 | flex: 1;
8 | .repl-string {
9 | word-break: break-all;
10 | .fa-play {
11 | font-size: 0.8em;
12 | padding-right: 6px;
13 | color: if($theme == $dark-theme, $dark-app-entry-message-output-arr-fold-color, $lt-app-entry-message-output-arr-fold-color);
14 | }
15 | .fa-play.fa-rotate-90 {
16 | position: relative;
17 | top: 2px;
18 | padding-top: 5px;
19 | padding-right: 6px;
20 | }
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/stylesheets/repl-output-url.scss:
--------------------------------------------------------------------------------
1 | @import 'themes';
2 | @import 'repl-common';
3 |
4 | @mixin replOutputURL($theme) {
5 |
6 | .repl-output-url {
7 |
8 | .repl-url {
9 | color: $app-external-link-color;
10 | .fa-external-link {
11 | padding: 0px 5px;
12 | cursor: pointer;
13 | color: $app-external-icon-color;
14 | position: relative;
15 | top: 1px;
16 | }
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/stylesheets/repl-output.scss:
--------------------------------------------------------------------------------
1 | @import 'repl-output-array';
2 | @import 'repl-output-object';
3 | @import 'repl-output-integer';
4 | @import 'repl-output-regex';
5 | @import 'repl-output-string';
6 | @import 'repl-output-color';
7 | @import 'repl-output-html';
8 | @import 'repl-output-url';
9 | @import 'repl-output-crypto';
10 | @import 'repl-output-buffer-explorer';
11 | @import 'repl-output-chart-viewer';
12 | @import 'repl-output-grid-viewer';
13 | @import 'clojurescript/repl-output-cljs-var';
14 | @import 'clojurescript/repl-output-cljs-val';
15 | @import 'clojurescript/repl-output-cljs-meta';
16 | @import 'clojurescript/repl-output-cljs-docs';
17 | @import 'clojurescript/repl-output-cljs-source';
18 | @import 'clojurescript/repl-output-cljs-wrapper';
19 |
20 | @mixin replOutput($theme) {
21 | @include replOutputArrayFold($theme);
22 | @include replOutputObjectFold($theme);
23 | @include replOutputInteger($theme);
24 | @include replOutputRegex($theme);
25 | @include replOutputString($theme);
26 | @include replOutputColor($theme);
27 | @include replOutputHTML($theme);
28 | @include replOutputBufferExplorer($theme);
29 | @include replOutputURL($theme);
30 | @include replOutputCrypto($theme);
31 | @include replOutputChartViewer($theme);
32 | @include replOutputGridViewer($theme);
33 | @include replOutputCljsVar($theme);
34 | @include replOutputCljsVal($theme);
35 | @include replOutputCljsMeta($theme);
36 | @include replOutputCljsDocs($theme);
37 | @include replOutputCljsSource($theme);
38 | @include replOutputCljsWrapper($theme);
39 | }
40 |
--------------------------------------------------------------------------------
/stylesheets/repl-preferences.scss:
--------------------------------------------------------------------------------
1 | @import 'themes';
2 | @import 'repl-common';
3 |
4 | @mixin preferences($theme) {
5 | .repl-preferences-panel {
6 | width: 100%;
7 | display: none;
8 | flex-direction: column;
9 | position: absolute;
10 | top: calc(100% - #{$app-font-size} - 6px);
11 | left: 0;
12 | height: 0px;
13 | z-index: 100;
14 | color: if($theme == $dark-theme, $dark-app-preference-color, $lt-app-preference-color );
15 | background-color: if($theme == $dark-theme, $dark-app-preference-background-color, $lt-app-preference-background-color );
16 | transition: all 0.5s cubic-bezier(0.55, 0.09, 0.68, 0.53);
17 |
18 | .repl-preferences-head {
19 | height: 40px;
20 | min-height: 40px;
21 | width: 100%;
22 | display:flex;
23 | background-color: if($theme == $dark-theme, $dark-app-preference-header-bg-color, $lt-app-preference-header-bg-color );
24 | .title {
25 | margin: auto;
26 | font-weight: 900;
27 | font-size: 1.2em;
28 | }
29 | .close-preference {
30 | color: if($theme == $dark-theme, $dark-app-preference-close-color, $lt-app-preference-close-color );
31 | cursor: pointer;
32 | display: flex;
33 | padding: 0px 10px;
34 | align-self: center;
35 | }
36 | }
37 |
38 | .repl-preferences-body {
39 | padding: 10px 20px;
40 | display: flex;
41 | flex-direction: column;
42 |
43 | .preference {
44 | flex: 1;
45 | display: flex;
46 | padding: 10px 0px;
47 | min-height: 20px;
48 | border-bottom: 1px solid if($theme == $dark-theme, $dark-app-preference-entry-border-color, $lt-app-preference-entry-border-color );
49 |
50 | .preference-name {
51 | margin: auto 0;
52 | flex-basis: 30%;
53 | font-weight: 900;
54 | min-width: 300px;
55 | .lang-img {
56 | position: relative;
57 | &.ts-img {
58 | top: 3px;
59 | left: 0px;
60 | }
61 | &.js-img {
62 | top: 4px;
63 | left: 0px;
64 | }
65 | &.cljs-img {
66 | top: 5px;
67 | left: -5px;
68 | }
69 | }
70 | }
71 | .preference-value {
72 | padding: 0px 5px;
73 | flex: 1;
74 | .textbox {
75 | }
76 |
77 | .radio-group {
78 | padding-right: 10px;
79 | }
80 |
81 | .checkbox-group {
82 | padding-right: 6px;
83 | display: inherit;
84 | line-height: 1.75em;
85 | }
86 |
87 | .fa {
88 | padding-left: 5px;
89 | }
90 |
91 | .fa-arrow-up {
92 | color: if($theme == $dark-theme, $dark-app-move-up-color, $lt-app-move-up-color );
93 | }
94 |
95 | .fa-arrow-down {
96 | color: if($theme == $dark-theme, $dark-app-move-down-color, $lt-app-move-down-color );
97 | }
98 | }
99 | }
100 |
101 | .statusbar-placeholder {
102 | height: calc(#{$app-font-size} + 20px);
103 | min-height: calc(#{$app-font-size} + 20px);
104 | }
105 |
106 | fieldset {
107 | border: none;
108 | padding: 0px;
109 | }
110 | }
111 | }
112 | .repl-preferences-panel.open {
113 | top: 0px;
114 | height: calc(100% - #{$app-font-size} - 6px);
115 | display: flex;
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/stylesheets/repl-prompt.scss:
--------------------------------------------------------------------------------
1 | @import 'themes';
2 | @import 'repl-common';
3 |
4 | @mixin replPrompt($theme) {
5 | .repl-prompt {
6 | margin: 0;
7 | padding: 5px;
8 | background-color: if($theme == $dark-theme, $dark-app-prompt-background-color, $lt-app-prompt-background-color);
9 | display: flex;
10 | align-items: flex-start;
11 | min-height: 25px;
12 |
13 | .repl-active-icon {
14 | @include notSelectable();
15 | color: if($theme == $dark-theme, $dark-app-prompt-active-icon-color, $lt-app-prompt-active-icon-color);
16 | @include arrowIcon();
17 | }
18 |
19 | .repl-active-input {
20 | @include entryLayout();
21 | @include editor();
22 | }
23 | .repl-active-input.repl-active-input-running:before {
24 | content: "\f021";
25 | float: right;
26 | margin-right: 8px;
27 | font: normal normal normal 14px/1 FontAwesome;
28 | color: if($theme == $dark-theme, $dark-app-prompt-spin-color, $lt-app-prompt-spin-color);
29 | animation: fa-spin 2s infinite linear;
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/stylesheets/repl-source-file.scss:
--------------------------------------------------------------------------------
1 | @import 'themes';
2 | @import 'repl-common';
3 |
4 | @mixin replSourceFile($theme) {
5 |
6 | .repl-source-access {
7 |
8 | .repl-source-file {
9 | color: $app-external-link-color;
10 | .fa-external-link {
11 | padding: 0px 5px;
12 | cursor: pointer;
13 | color: $app-external-icon-color;
14 | position: relative;
15 | top: 1px;
16 | }
17 | }
18 | .repl-no-source-file {
19 | .name {
20 | color: $app-text-error-color;
21 | }
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/stylesheets/repl-status-bar.scss:
--------------------------------------------------------------------------------
1 | @import 'themes';
2 | @import 'repl-common';
3 |
4 | @keyframes spin {
5 | 0% {
6 | -webkit-transform: rotate(-30deg);
7 | transform: rotate(-30deg);
8 | }
9 |
10 | 100% {
11 | -webkit-transform: rotate(30deg);
12 | transform: rotate(30deg);
13 | }
14 | }
15 |
16 | @mixin statusBar($theme) {
17 | .repl-status-bar {
18 | @include notSelectable();
19 | z-index: 101;
20 | position: fixed;
21 | bottom: 0;
22 | left: 0;
23 | padding: 3px 10px;
24 | background-color: if($theme == $dark-theme, $dark-app-status-bar-background-color, $lt-app-status-bar-background-color );
25 | width: 100%;
26 | display: flex;
27 | align-items: center;
28 |
29 | .repl-status-bar-preference {
30 | padding-right: 10px;
31 | font-size: 1.3em;
32 | i.fa-cog {
33 | cursor: pointer;
34 | &:hover {
35 | animation: fa-spin 2s 1 linear;
36 | }
37 | }
38 | }
39 |
40 | .run-help {
41 | padding: 0px 25px;
42 | cursor: default;
43 | color: if($theme == $dark-theme, $dark-app-status-bar-run-help-color, $lt-app-status-bar-run-help-color);
44 | .run-command {
45 | color: if($theme == $dark-theme, $dark-app-status-bar-run-color, $lt-app-status-bar-run-color);
46 | font-size: 0.9em;
47 | font-weight: 900;
48 | font-style: normal;
49 | }
50 | .run {
51 | font-weight: 900;
52 | }
53 | }
54 |
55 | .placeholder {
56 | flex: 1;
57 | }
58 |
59 | .repl-status-bar-commands {
60 | color: if($theme == $dark-theme, $dark-app-status-bar-command-color, $lt-app-status-bar-command-color);
61 | padding: 0 5px;
62 | }
63 |
64 | .repl-status-bar-errors {
65 | color: if($theme == $dark-theme, $dark-app-status-bar-error-color, $lt-app-status-bar-error-color);
66 | padding: 0 5px;
67 | }
68 |
69 | .repl-status-bar-handles {
70 | color: if($theme == $dark-theme, $dark-app-status-bar-handle-color, $lt-app-status-bar-handle-color);
71 | padding: 0 5px;
72 | }
73 |
74 | .repl-status-bar-count,
75 | .repl-status-bar-message {
76 | pointer-events: none;
77 | color: if($theme == $dark-theme, $dark-app-status-bar-message-color, $lt-app-status-bar-message-color);
78 | padding: 0 5px;
79 | }
80 | .repl-status-bar-img {
81 | display: flex;
82 | align-self: center;
83 | }
84 |
85 | .console-notification {
86 | font-size: 0.8em;
87 | color: if($theme == $dark-theme, $dark-app-status-bar-console-notification-color, $lt-app-status-bar-console-notification-color);
88 | -webkit-animation:spin 0.5s linear infinite;
89 | animation:spin 0.5s linear infinite;
90 | -webkit-animation-direction: alternate;
91 | animation-direction: alternate;
92 | }
93 |
94 | .repl-status-cursor-position {
95 | color: if($theme == $dark-theme, $dark-app-status-bar-cursor-pos-color, $lt-app-status-bar-cursor-pos-color);
96 | cursor: default;
97 | }
98 |
99 | .console-release-notification {
100 | cursor: pointer;
101 | color: if($theme == $dark-theme, $dark-app-status-bar-console-release-notification-color, $lt-app-status-bar-console-release-notification-color);
102 | padding: 0 5px;
103 | }
104 |
105 | .repl-status-bar-console {
106 | color: if($theme == $dark-theme, $dark-app-status-bar-console-color, $lt-app-status-bar-console-color);
107 | padding-right: 15px;
108 | cursor: pointer;
109 |
110 | .fa-stack {
111 | .text-danger {
112 | color: if($theme == $dark-theme, $dark-app-entry-status-error-color, $lt-app-entry-status-error-color);
113 | }
114 |
115 | .fa-terminal {
116 | font-weight: 900;
117 | }
118 | }
119 | }
120 |
121 | .repl-status-bar-mode {
122 | color: if($theme == $dark-theme, $dark-app-status-bar-mode-color, $lt-app-status-bar-mode-color);
123 | padding: 0 5px;
124 |
125 | .fa {
126 | padding: 0 3px;
127 | }
128 | }
129 |
130 | .repl-status-bar-lang {
131 | color: if($theme == $dark-theme, $dark-app-status-bar-lang-color, $lt-app-status-bar-lang-color);
132 | padding: 0 5px;
133 |
134 | .fa, .icon-javascript {
135 | padding: 0 3px;
136 | font-size: 1.1em;
137 | }
138 | .icon-javascript {
139 | position: relative;
140 | top: 1px;
141 | }
142 | }
143 |
144 | }
145 |
146 | .repl-status-bar {
147 | height: calc(#{$app-font-size} + 6px);
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/stylesheets/repl-suggestions.scss:
--------------------------------------------------------------------------------
1 | @import 'themes';
2 |
3 | @mixin suggestions($theme) {
4 | .repl-prompt-suggestion-wrapper {
5 | position: absolute;
6 | background-color: if($theme == $dark-theme, $dark-app-suggestion-background-color, $lt-app-suggestion-background-color);
7 | z-index: 100;
8 | .repl-prompt-suggestion-list {
9 | font-size: 0.9em;
10 | [data-selected='true'] {
11 | background-color: lighten(if($theme == $dark-theme, $dark-app-background-color, $lt-app-background-color), 10%);
12 | }
13 | margin: 0;
14 | // dont change this
15 | max-height: 200px;
16 |
17 | // dont change this
18 | max-width: 300px;
19 | overflow: auto;
20 | border: 2px solid if($theme == $dark-theme, $dark-app-suggestion-border-color, $lt-app-suggestion-border-color);
21 | border-radius: 5px;
22 | padding: 2px 0;
23 |
24 | .repl-prompt-suggestion {
25 | min-height: calc(#{$app-font-size} + 8px);
26 | max-height: calc(#{$app-font-size} + 8px);
27 | display: flex;
28 | padding: 4px 2px;
29 | border-bottom: 1px solid if($theme == $dark-theme, $dark-app-suggestion-entry-border-color, $lt-app-suggestion-entry-border-color);
30 | cursor: pointer;
31 |
32 | .repl-prompt-suggestion-type {
33 | padding: 2px;
34 | font-weight: 900;
35 | border-radius: 100%;
36 | width: $app-font-size;
37 | height: $app-font-size;
38 | min-height: calc(#{$app-font-size} + 8px);
39 | max-height: calc(#{$app-font-size} + 8px);
40 | text-align: center;
41 | display: inline-block;
42 | color: if($theme == $dark-theme, $dark-app-suggestion-type-color, $lt-app-suggestion-type-color);
43 | font-family: if($theme == $dark-theme, $dark-app-suggestion-type-font-family, $lt-app-suggestion-type-font-family);
44 | background-color: if($theme == $dark-theme, $dark-app-suggestion-type-background-color, $lt-app-suggestion-type-background-color);
45 | }
46 |
47 | .repl-prompt-suggestion-text {
48 | width: 100%;
49 | height: 100%;
50 | padding: 2px 8px;
51 | display: inline-block;
52 | text-overflow: ellipsis;
53 | overflow: hidden;
54 | flex: 1;
55 |
56 | .repl-prompt-suggestion-highlight {
57 | white-space: nowrap;
58 | color: if($theme == $dark-theme, $dark-app-suggestion-type-hightlight-color, $lt-app-suggestion-type-hightlight-color);
59 | }
60 |
61 | .repl-prompt-suggestion-expect {
62 | white-space: nowrap;
63 | color: if($theme == $dark-theme, $dark-app-suggestion-type-expect-color, $lt-app-suggestion-type-expect-color);
64 | }
65 | }
66 |
67 | &:last-child {
68 | border-bottom: none;
69 | }
70 | }
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/stylesheets/repl.scss:
--------------------------------------------------------------------------------
1 | @import 'themes';
2 | @import 'repl-common';
3 | @import 'repl-container-left';
4 | @import 'repl-container-right';
5 | @import 'repl-status-bar';
6 | @import 'repl-suggestions';
7 | @import 'repl-preferences';
8 | @import 'repl-editor';
9 |
10 | html{
11 | height: 100%;
12 | }
13 |
14 | @mixin repl($theme) {
15 | #node-repl-plus {
16 | font-size: 0.9em;
17 | margin: 5px 0px;
18 | @include selectable();
19 |
20 | .repl-container {
21 | display: flex;
22 | @include containerLeft($theme);
23 | @include containerRight($theme);
24 | @include statusBar($theme);
25 | }
26 | }
27 |
28 | #node-repl-prompt-suggestions {
29 | @include suggestions($theme);
30 | }
31 |
32 | #node-repl-preferences {
33 | @include preferences($theme);
34 | }
35 | @include replEditor($theme);
36 | }
37 |
38 | body {
39 | min-height: 100%;
40 | max-height: 100%;
41 | margin: 0;
42 | font-size: $app-font-size;
43 | font-family: $app-font-family;
44 | -webkit-font-feature-settings: 'liga' 1, 'kern' 1;
45 | font-feature-settings: 'liga' 1, 'kern' 1;
46 | @include notSelectable();
47 |
48 | &:before {
49 | content: attr(data-watermark-logo);
50 | position: fixed;
51 | top: 40vh;
52 | // 2 characters
53 | left: calc((100vw - 20vh * 2 / 2)/2);
54 | font-size: 20vh;
55 | font-family: 'Josefin Sans', sans-serif;
56 | pointer-events: none;
57 | z-index: 10;
58 | }
59 | &:after {
60 | content: attr(data-watermark-msg);
61 | position: fixed;
62 | top: 56vh;
63 | // 16 characters
64 | left: calc((100vw - 2vh * 16 / 2)/2);
65 | font-size: 2vh;
66 | pointer-events: none;
67 | z-index: 10;
68 | }
69 | }
70 |
71 | body.dark-theme {
72 | background-color: $dark-app-background-color;
73 | color: $dark-app-color;
74 | &:before, &:after {
75 | color: $dark-app-water-mark-color;
76 | }
77 | @include repl($dark-theme);
78 | }
79 |
80 | body.light-theme {
81 | background-color: $lt-app-background-color;
82 | color: $lt-app-color;
83 | &:before, &:after {
84 | color: $lt-app-water-mark-color;
85 | }
86 | @include repl($light-theme);
87 | }
88 |
89 | pre {
90 | @include editor();
91 | }
92 |
93 | ::selection {
94 | background-color: $app-text-selection-background-color;
95 | color: $app-text-selection-color;
96 | }
97 |
98 | .hide {
99 | display: none !important;
100 | }
101 |
--------------------------------------------------------------------------------
/stylesheets/themes.scss:
--------------------------------------------------------------------------------
1 | @import 'configs';
2 | @import 'dark-theme';
3 | @import 'light-theme';
4 |
--------------------------------------------------------------------------------