├── .gitignore ├── LICENSE ├── README.md ├── doc └── intro.md ├── project.clj ├── resources ├── codemirror.css └── html │ └── index.html ├── script ├── brepl.clj └── build.clj ├── session.iml ├── src └── session │ ├── app.cljs │ ├── core.clj │ ├── editor.cljs │ ├── eval.cljs │ ├── io.cljs │ ├── loop.cljs │ ├── main.cljs │ └── system.cljs └── test └── session └── core_test.clj /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /classes 3 | /checkouts 4 | /resources/js/* 5 | pom.xml 6 | pom.xml.asc 7 | *.jar 8 | *.class 9 | /.lein-* 10 | /.nrepl-port 11 | .repl* 12 | .idea/ 13 | gamma.iml -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC 2 | LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM 3 | CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 4 | 5 | 1. DEFINITIONS 6 | 7 | "Contribution" means: 8 | 9 | a) in the case of the initial Contributor, the initial code and 10 | documentation distributed under this Agreement, and 11 | 12 | b) in the case of each subsequent Contributor: 13 | 14 | i) changes to the Program, and 15 | 16 | ii) additions to the Program; 17 | 18 | where such changes and/or additions to the Program originate from and are 19 | distributed by that particular Contributor. A Contribution 'originates' from 20 | a Contributor if it was added to the Program by such Contributor itself or 21 | anyone acting on such Contributor's behalf. Contributions do not include 22 | additions to the Program which: (i) are separate modules of software 23 | distributed in conjunction with the Program under their own license 24 | agreement, and (ii) are not derivative works of the Program. 25 | 26 | "Contributor" means any person or entity that distributes the Program. 27 | 28 | "Licensed Patents" mean patent claims licensable by a Contributor which are 29 | necessarily infringed by the use or sale of its Contribution alone or when 30 | combined with the Program. 31 | 32 | "Program" means the Contributions distributed in accordance with this 33 | Agreement. 34 | 35 | "Recipient" means anyone who receives the Program under this Agreement, 36 | including all Contributors. 37 | 38 | 2. GRANT OF RIGHTS 39 | 40 | a) Subject to the terms of this Agreement, each Contributor hereby grants 41 | Recipient a non-exclusive, worldwide, royalty-free copyright license to 42 | reproduce, prepare derivative works of, publicly display, publicly perform, 43 | distribute and sublicense the Contribution of such Contributor, if any, and 44 | such derivative works, in source code and object code form. 45 | 46 | b) Subject to the terms of this Agreement, each Contributor hereby grants 47 | Recipient a non-exclusive, worldwide, royalty-free patent license under 48 | Licensed Patents to make, use, sell, offer to sell, import and otherwise 49 | transfer the Contribution of such Contributor, if any, in source code and 50 | object code form. This patent license shall apply to the combination of the 51 | Contribution and the Program if, at the time the Contribution is added by the 52 | Contributor, such addition of the Contribution causes such combination to be 53 | covered by the Licensed Patents. The patent license shall not apply to any 54 | other combinations which include the Contribution. No hardware per se is 55 | licensed hereunder. 56 | 57 | c) Recipient understands that although each Contributor grants the licenses 58 | to its Contributions set forth herein, no assurances are provided by any 59 | Contributor that the Program does not infringe the patent or other 60 | intellectual property rights of any other entity. Each Contributor disclaims 61 | any liability to Recipient for claims brought by any other entity based on 62 | infringement of intellectual property rights or otherwise. As a condition to 63 | exercising the rights and licenses granted hereunder, each Recipient hereby 64 | assumes sole responsibility to secure any other intellectual property rights 65 | needed, if any. For example, if a third party patent license is required to 66 | allow Recipient to distribute the Program, it is Recipient's responsibility 67 | to acquire that license before distributing the Program. 68 | 69 | d) Each Contributor represents that to its knowledge it has sufficient 70 | copyright rights in its Contribution, if any, to grant the copyright license 71 | set forth in this Agreement. 72 | 73 | 3. REQUIREMENTS 74 | 75 | A Contributor may choose to distribute the Program in object code form under 76 | its own license agreement, provided that: 77 | 78 | a) it complies with the terms and conditions of this Agreement; and 79 | 80 | b) its license agreement: 81 | 82 | i) effectively disclaims on behalf of all Contributors all warranties and 83 | conditions, express and implied, including warranties or conditions of title 84 | and non-infringement, and implied warranties or conditions of merchantability 85 | and fitness for a particular purpose; 86 | 87 | ii) effectively excludes on behalf of all Contributors all liability for 88 | damages, including direct, indirect, special, incidental and consequential 89 | damages, such as lost profits; 90 | 91 | iii) states that any provisions which differ from this Agreement are offered 92 | by that Contributor alone and not by any other party; and 93 | 94 | iv) states that source code for the Program is available from such 95 | Contributor, and informs licensees how to obtain it in a reasonable manner on 96 | or through a medium customarily used for software exchange. 97 | 98 | When the Program is made available in source code form: 99 | 100 | a) it must be made available under this Agreement; and 101 | 102 | b) a copy of this Agreement must be included with each copy of the Program. 103 | 104 | Contributors may not remove or alter any copyright notices contained within 105 | the Program. 106 | 107 | Each Contributor must identify itself as the originator of its Contribution, 108 | if any, in a manner that reasonably allows subsequent Recipients to identify 109 | the originator of the Contribution. 110 | 111 | 4. COMMERCIAL DISTRIBUTION 112 | 113 | Commercial distributors of software may accept certain responsibilities with 114 | respect to end users, business partners and the like. While this license is 115 | intended to facilitate the commercial use of the Program, the Contributor who 116 | includes the Program in a commercial product offering should do so in a 117 | manner which does not create potential liability for other Contributors. 118 | Therefore, if a Contributor includes the Program in a commercial product 119 | offering, such Contributor ("Commercial Contributor") hereby agrees to defend 120 | and indemnify every other Contributor ("Indemnified Contributor") against any 121 | losses, damages and costs (collectively "Losses") arising from claims, 122 | lawsuits and other legal actions brought by a third party against the 123 | Indemnified Contributor to the extent caused by the acts or omissions of such 124 | Commercial Contributor in connection with its distribution of the Program in 125 | a commercial product offering. The obligations in this section do not apply 126 | to any claims or Losses relating to any actual or alleged intellectual 127 | property infringement. In order to qualify, an Indemnified Contributor must: 128 | a) promptly notify the Commercial Contributor in writing of such claim, and 129 | b) allow the Commercial Contributor tocontrol, and cooperate with the 130 | Commercial Contributor in, the defense and any related settlement 131 | negotiations. The Indemnified Contributor may participate in any such claim 132 | at its own expense. 133 | 134 | For example, a Contributor might include the Program in a commercial product 135 | offering, Product X. That Contributor is then a Commercial Contributor. If 136 | that Commercial Contributor then makes performance claims, or offers 137 | warranties related to Product X, those performance claims and warranties are 138 | such Commercial Contributor's responsibility alone. Under this section, the 139 | Commercial Contributor would have to defend claims against the other 140 | Contributors related to those performance claims and warranties, and if a 141 | court requires any other Contributor to pay any damages as a result, the 142 | Commercial Contributor must pay those damages. 143 | 144 | 5. NO WARRANTY 145 | 146 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON 147 | AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER 148 | EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR 149 | CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A 150 | PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the 151 | appropriateness of using and distributing the Program and assumes all risks 152 | associated with its exercise of rights under this Agreement , including but 153 | not limited to the risks and costs of program errors, compliance with 154 | applicable laws, damage to or loss of data, programs or equipment, and 155 | unavailability or interruption of operations. 156 | 157 | 6. DISCLAIMER OF LIABILITY 158 | 159 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY 160 | CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, 161 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION 162 | LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 163 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 164 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE 165 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY 166 | OF SUCH DAMAGES. 167 | 168 | 7. GENERAL 169 | 170 | If any provision of this Agreement is invalid or unenforceable under 171 | applicable law, it shall not affect the validity or enforceability of the 172 | remainder of the terms of this Agreement, and without further action by the 173 | parties hereto, such provision shall be reformed to the minimum extent 174 | necessary to make such provision valid and enforceable. 175 | 176 | If Recipient institutes patent litigation against any entity (including a 177 | cross-claim or counterclaim in a lawsuit) alleging that the Program itself 178 | (excluding combinations of the Program with other software or hardware) 179 | infringes such Recipient's patent(s), then such Recipient's rights granted 180 | under Section 2(b) shall terminate as of the date such litigation is filed. 181 | 182 | All Recipient's rights under this Agreement shall terminate if it fails to 183 | comply with any of the material terms or conditions of this Agreement and 184 | does not cure such failure in a reasonable period of time after becoming 185 | aware of such noncompliance. If all Recipient's rights under this Agreement 186 | terminate, Recipient agrees to cease use and distribution of the Program as 187 | soon as reasonably practicable. However, Recipient's obligations under this 188 | Agreement and any licenses granted by Recipient relating to the Program shall 189 | continue and survive. 190 | 191 | Everyone is permitted to copy and distribute copies of this Agreement, but in 192 | order to avoid inconsistency the Agreement is copyrighted and may only be 193 | modified in the following manner. The Agreement Steward reserves the right to 194 | publish new versions (including revisions) of this Agreement from time to 195 | time. No one other than the Agreement Steward has the right to modify this 196 | Agreement. The Eclipse Foundation is the initial Agreement Steward. The 197 | Eclipse Foundation may assign the responsibility to serve as the Agreement 198 | Steward to a suitable separate entity. Each new version of the Agreement will 199 | be given a distinguishing version number. The Program (including 200 | Contributions) may always be distributed subject to the version of the 201 | Agreement under which it was received. In addition, after a new version of 202 | the Agreement is published, Contributor may elect to distribute the Program 203 | (including its Contributions) under the new version. Except as expressly 204 | stated in Sections 2(a) and 2(b) above, Recipient receives no rights or 205 | licenses to the intellectual property of any Contributor under this 206 | Agreement, whether expressly, by implication, estoppel or otherwise. All 207 | rights in the Program not expressly granted under this Agreement are 208 | reserved. 209 | 210 | This Agreement is governed by the laws of the State of New York and the 211 | intellectual property laws of the United States of America. No party to this 212 | Agreement will bring a legal action under this Agreement more than one year 213 | after the cause of action arose. Each party waives its rights to a jury trial 214 | in any resulting litigation. 215 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # session 2 | 3 | A Clojure library designed to ... well, that part is up to you. 4 | 5 | ## Usage 6 | 7 | FIXME 8 | 9 | ## License 10 | 11 | Copyright © 2015 FIXME 12 | 13 | Distributed under the Eclipse Public License either version 1.0 or (at 14 | your option) any later version. 15 | -------------------------------------------------------------------------------- /doc/intro.md: -------------------------------------------------------------------------------- 1 | # Introduction to session 2 | 3 | TODO: write [great documentation](http://jacobian.org/writing/what-to-write/) 4 | -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject session "0.1.0-SNAPSHOT" 2 | :description "FIXME: write description" 3 | :url "http://example.com/FIXME" 4 | :license {:name "Eclipse Public License" 5 | :url "http://www.eclipse.org/legal/epl-v10.html"} 6 | :dependencies [[org.clojure/clojure "1.7.0"] 7 | [org.clojure/clojurescript "1.7.28"] 8 | [cljsjs/codemirror "5.1.0-2"] 9 | [org.omcljs/om "0.9.0"] 10 | [com.lucasbradstreet/cljs-uuid-utils "1.0.2"]]) 11 | -------------------------------------------------------------------------------- /resources/codemirror.css: -------------------------------------------------------------------------------- 1 | /* BASICS */ 2 | 3 | .CodeMirror { 4 | /* Set height, width, borders, and global font properties here */ 5 | font-family: monospace; 6 | height: 300px; 7 | color: black; 8 | } 9 | 10 | /* PADDING */ 11 | 12 | .CodeMirror-lines { 13 | padding: 4px 0; /* Vertical padding around content */ 14 | } 15 | .CodeMirror pre { 16 | padding: 0 4px; /* Horizontal padding of content */ 17 | } 18 | 19 | .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { 20 | background-color: white; /* The little square between H and V scrollbars */ 21 | } 22 | 23 | /* GUTTER */ 24 | 25 | .CodeMirror-gutters { 26 | border-right: 1px solid #ddd; 27 | background-color: #f7f7f7; 28 | white-space: nowrap; 29 | } 30 | .CodeMirror-linenumbers {} 31 | .CodeMirror-linenumber { 32 | padding: 0 3px 0 5px; 33 | min-width: 20px; 34 | text-align: right; 35 | color: #999; 36 | white-space: nowrap; 37 | } 38 | 39 | .CodeMirror-guttermarker { color: black; } 40 | .CodeMirror-guttermarker-subtle { color: #999; } 41 | 42 | /* CURSOR */ 43 | 44 | .CodeMirror div.CodeMirror-cursor { 45 | border-left: 1px solid black; 46 | } 47 | /* Shown when moving in bi-directional text */ 48 | .CodeMirror div.CodeMirror-secondarycursor { 49 | border-left: 1px solid silver; 50 | } 51 | .CodeMirror.cm-fat-cursor div.CodeMirror-cursor { 52 | width: auto; 53 | border: 0; 54 | background: #7e7; 55 | } 56 | .CodeMirror.cm-fat-cursor div.CodeMirror-cursors { 57 | z-index: 1; 58 | } 59 | 60 | .cm-animate-fat-cursor { 61 | width: auto; 62 | border: 0; 63 | -webkit-animation: blink 1.06s steps(1) infinite; 64 | -moz-animation: blink 1.06s steps(1) infinite; 65 | animation: blink 1.06s steps(1) infinite; 66 | } 67 | @-moz-keyframes blink { 68 | 0% { background: #7e7; } 69 | 50% { background: none; } 70 | 100% { background: #7e7; } 71 | } 72 | @-webkit-keyframes blink { 73 | 0% { background: #7e7; } 74 | 50% { background: none; } 75 | 100% { background: #7e7; } 76 | } 77 | @keyframes blink { 78 | 0% { background: #7e7; } 79 | 50% { background: none; } 80 | 100% { background: #7e7; } 81 | } 82 | 83 | /* Can style cursor different in overwrite (non-insert) mode */ 84 | div.CodeMirror-overwrite div.CodeMirror-cursor {} 85 | 86 | .cm-tab { display: inline-block; text-decoration: inherit; } 87 | 88 | .CodeMirror-ruler { 89 | border-left: 1px solid #ccc; 90 | position: absolute; 91 | } 92 | 93 | /* DEFAULT THEME */ 94 | 95 | .cm-s-default .cm-keyword {color: #708;} 96 | .cm-s-default .cm-atom {color: #219;} 97 | .cm-s-default .cm-number {color: #164;} 98 | .cm-s-default .cm-def {color: #00f;} 99 | .cm-s-default .cm-variable, 100 | .cm-s-default .cm-punctuation, 101 | .cm-s-default .cm-property, 102 | .cm-s-default .cm-operator {} 103 | .cm-s-default .cm-variable-2 {color: #05a;} 104 | .cm-s-default .cm-variable-3 {color: #085;} 105 | .cm-s-default .cm-comment {color: #a50;} 106 | .cm-s-default .cm-string {color: #a11;} 107 | .cm-s-default .cm-string-2 {color: #f50;} 108 | .cm-s-default .cm-meta {color: #555;} 109 | .cm-s-default .cm-qualifier {color: #555;} 110 | .cm-s-default .cm-builtin {color: #30a;} 111 | .cm-s-default .cm-bracket {color: #997;} 112 | .cm-s-default .cm-tag {color: #170;} 113 | .cm-s-default .cm-attribute {color: #00c;} 114 | .cm-s-default .cm-header {color: blue;} 115 | .cm-s-default .cm-quote {color: #090;} 116 | .cm-s-default .cm-hr {color: #999;} 117 | .cm-s-default .cm-link {color: #00c;} 118 | 119 | .cm-negative {color: #d44;} 120 | .cm-positive {color: #292;} 121 | .cm-header, .cm-strong {font-weight: bold;} 122 | .cm-em {font-style: italic;} 123 | .cm-link {text-decoration: underline;} 124 | .cm-strikethrough {text-decoration: line-through;} 125 | 126 | .cm-s-default .cm-error {color: #f00;} 127 | .cm-invalidchar {color: #f00;} 128 | 129 | /* Default styles for common addons */ 130 | 131 | div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;} 132 | div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} 133 | .CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); } 134 | .CodeMirror-activeline-background {background: #e8f2ff;} 135 | 136 | /* STOP */ 137 | 138 | /* The rest of this file contains styles related to the mechanics of 139 | the editor. You probably shouldn't touch them. */ 140 | 141 | .CodeMirror { 142 | position: relative; 143 | overflow: hidden; 144 | background: white; 145 | /* resize */ 146 | border: 1px solid #eee; 147 | height: auto; 148 | } 149 | 150 | .CodeMirror-scroll { 151 | overflow: scroll !important; /* Things will break if this is overridden */ 152 | /* 30px is the magic margin used to hide the element's real scrollbars */ 153 | /* See overflow: hidden in .CodeMirror */ 154 | margin-bottom: -30px; margin-right: -30px; 155 | padding-bottom: 30px; 156 | height: 100%; 157 | outline: none; /* Prevent dragging from highlighting the element */ 158 | position: relative; 159 | } 160 | .CodeMirror-sizer { 161 | position: relative; 162 | border-right: 30px solid transparent; 163 | } 164 | 165 | /* The fake, visible scrollbars. Used to force redraw during scrolling 166 | before actuall scrolling happens, thus preventing shaking and 167 | flickering artifacts. */ 168 | .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { 169 | position: absolute; 170 | z-index: 6; 171 | display: none; 172 | } 173 | .CodeMirror-vscrollbar { 174 | right: 0; top: 0; 175 | overflow-x: hidden; 176 | overflow-y: scroll; 177 | } 178 | .CodeMirror-hscrollbar { 179 | bottom: 0; left: 0; 180 | overflow-y: hidden; 181 | overflow-x: scroll; 182 | } 183 | .CodeMirror-scrollbar-filler { 184 | right: 0; bottom: 0; 185 | } 186 | .CodeMirror-gutter-filler { 187 | left: 0; bottom: 0; 188 | } 189 | 190 | .CodeMirror-gutters { 191 | position: absolute; left: 0; top: 0; 192 | z-index: 3; 193 | } 194 | .CodeMirror-gutter { 195 | white-space: normal; 196 | height: 100%; 197 | display: inline-block; 198 | margin-bottom: -30px; 199 | /* Hack to make IE7 behave */ 200 | *zoom:1; 201 | *display:inline; 202 | } 203 | .CodeMirror-gutter-wrapper { 204 | position: absolute; 205 | z-index: 4; 206 | height: 100%; 207 | } 208 | .CodeMirror-gutter-elt { 209 | position: absolute; 210 | cursor: default; 211 | z-index: 4; 212 | } 213 | .CodeMirror-gutter-wrapper { 214 | -webkit-user-select: none; 215 | -moz-user-select: none; 216 | user-select: none; 217 | } 218 | 219 | .CodeMirror-lines { 220 | cursor: text; 221 | min-height: 1px; /* prevents collapsing before first draw */ 222 | } 223 | .CodeMirror pre { 224 | /* Reset some styles that the rest of the page might have set */ 225 | -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; 226 | border-width: 0; 227 | background: transparent; 228 | font-family: inherit; 229 | font-size: inherit; 230 | margin: 0; 231 | white-space: pre; 232 | word-wrap: normal; 233 | line-height: inherit; 234 | color: inherit; 235 | z-index: 2; 236 | position: relative; 237 | overflow: visible; 238 | -webkit-tap-highlight-color: transparent; 239 | } 240 | .CodeMirror-wrap pre { 241 | word-wrap: break-word; 242 | white-space: pre-wrap; 243 | word-break: normal; 244 | } 245 | 246 | .CodeMirror-linebackground { 247 | position: absolute; 248 | left: 0; right: 0; top: 0; bottom: 0; 249 | z-index: 0; 250 | } 251 | 252 | .CodeMirror-linewidget { 253 | position: relative; 254 | z-index: 2; 255 | overflow: auto; 256 | } 257 | 258 | .CodeMirror-widget {} 259 | 260 | .CodeMirror-code { 261 | outline: none; 262 | } 263 | 264 | /* Force content-box sizing for the elements where we expect it */ 265 | .CodeMirror-scroll, 266 | .CodeMirror-sizer, 267 | .CodeMirror-gutter, 268 | .CodeMirror-gutters, 269 | .CodeMirror-linenumber { 270 | -moz-box-sizing: content-box; 271 | box-sizing: content-box; 272 | } 273 | 274 | .CodeMirror-measure { 275 | position: absolute; 276 | width: 100%; 277 | height: 0; 278 | overflow: hidden; 279 | visibility: hidden; 280 | } 281 | .CodeMirror-measure pre { position: static; } 282 | 283 | .CodeMirror div.CodeMirror-cursor { 284 | position: absolute; 285 | border-right: none; 286 | width: 0; 287 | } 288 | 289 | div.CodeMirror-cursors { 290 | visibility: hidden; 291 | position: relative; 292 | z-index: 3; 293 | } 294 | .CodeMirror-focused div.CodeMirror-cursors { 295 | visibility: visible; 296 | } 297 | 298 | .CodeMirror-selected { background: #d9d9d9; } 299 | .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; } 300 | .CodeMirror-crosshair { cursor: crosshair; } 301 | .CodeMirror ::selection { background: #d7d4f0; } 302 | .CodeMirror ::-moz-selection { background: #d7d4f0; } 303 | 304 | .cm-searching { 305 | background: #ffa; 306 | background: rgba(255, 255, 0, .4); 307 | } 308 | 309 | /* IE7 hack to prevent it from returning funny offsetTops on the spans */ 310 | .CodeMirror span { *vertical-align: text-bottom; } 311 | 312 | /* Used to force a border model for a node */ 313 | .cm-force-border { padding-right: .1px; } 314 | 315 | @media print { 316 | /* Hide the cursor when printing */ 317 | .CodeMirror div.CodeMirror-cursors { 318 | visibility: hidden; 319 | } 320 | } 321 | 322 | /* See issue #2901 */ 323 | .cm-tab-wrap-hack:after { content: ''; } 324 | 325 | /* Help users use markselection to safely style text background */ 326 | span.CodeMirror-selectedtext { background: none; } 327 | -------------------------------------------------------------------------------- /resources/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |

Session

10 | github
11 | Shift+Enter to evaluate 12 |
13 |
14 | 15 |
16 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /script/brepl.clj: -------------------------------------------------------------------------------- 1 | (require '[cljs.build.api :as b]) 2 | (require '[cljs.repl :as repl]) 3 | (require '[cljs.repl.browser :as browser]) 4 | 5 | (b/build (b/inputs "src") 6 | {:main 'session.main 7 | :asset-path "/js" 8 | :output-to "resources/js/main.js" 9 | :output-dir "resources/js" 10 | :verbose true 11 | :static-fns true 12 | :optimizations :simple}) 13 | 14 | (cljs.repl/repl 15 | (browser/repl-env 16 | :static-dir ["resources/html" "resources"]) 17 | :output-dir "resources/js" 18 | :asset-path "js" 19 | :static-fns true) -------------------------------------------------------------------------------- /script/build.clj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kovasb/session/f14f182f8dfa0c33345bee71d880df8f3b9e744b/script/build.clj -------------------------------------------------------------------------------- /session.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/session/app.cljs: -------------------------------------------------------------------------------- 1 | (ns session.app 2 | (:require 3 | [om.core :as om] 4 | [om.dom :as dom] 5 | [session.loop :as loop])) 6 | 7 | 8 | (defn create-manager [data owner] 9 | (reify om/IRender 10 | (render [_] 11 | (dom/div 12 | nil 13 | #_(str "last: " (:last-saved data)) 14 | (dom/input 15 | #js {:type "button" 16 | :value "save" 17 | :style #js {:margin-top "5px" 18 | :margin-bottom "5px"} 19 | :onClick (fn [x] 20 | ((om/get-shared owner :save)))}) 21 | #_(dom/input 22 | #js {:type "submit" 23 | :value "restore" 24 | :onClick (fn [x] 25 | ((om/get-shared owner :restore) 26 | (:last-saved data)))}))))) 27 | 28 | 29 | (defn create-loops [data owner] 30 | (reify om/IRender 31 | (render [_] 32 | (dom/div 33 | nil 34 | (om/build create-manager data) 35 | (apply dom/div nil 36 | (map #(om/build loop/create-loop % {:react-key (:id %)}) 37 | (:loops data))) 38 | (dom/input 39 | #js {:type "button" 40 | :value "insert" 41 | :style #js {:margin-top "20px" 42 | :margin-bottom "5px"} 43 | :onClick (fn [x] 44 | ((om/get-shared owner :loop-insert) 45 | :last))}))))) 46 | 47 | 48 | (defn main [system element-id] 49 | (om/root 50 | create-loops 51 | (:app-state system) 52 | {:target (. js/document (getElementById element-id)) 53 | :shared system})) 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /src/session/core.clj: -------------------------------------------------------------------------------- 1 | (ns session.core) 2 | 3 | (defn foo 4 | "I don't do a whole lot." 5 | [x] 6 | (println x "Hello, World!")) 7 | 8 | (defn foo [] 9 | ) 10 | 11 | (defn foo 12 | ) -------------------------------------------------------------------------------- /src/session/editor.cljs: -------------------------------------------------------------------------------- 1 | (ns session.editor 2 | (:require 3 | [om.core :as om] 4 | [om.dom :as dom] 5 | [cljsjs.codemirror])) 6 | 7 | 8 | (defn cm-view [data owner] 9 | (reify 10 | om/IRender 11 | (render [this] 12 | (dom/textarea nil (:text data))))) 13 | 14 | 15 | (defn shift-enter-fn [owner handler] 16 | (fn [cm] 17 | (let [output (pr-str ((om/get-shared owner :eval) (.getValue cm)))] 18 | (println output) 19 | (handler output)))) 20 | 21 | 22 | (defn create-editor [x owner opts] 23 | (reify 24 | om/IRender 25 | (render [_] 26 | (dom/span 27 | #js {:style #js {:padding "-0.4em" :display "inline-block" "min-width" "500px"}} 28 | (dom/textarea 29 | #js {:ref "theInput" 30 | :style 31 | #js {:padding "-0.4em" 32 | :display "inline-block" 33 | "min-width" "500px"}} 34 | (om/value (:text x))))) 35 | 36 | om/IDidUpdate 37 | (did-update [this prev-state prev-props] 38 | (let [cm-map (om/get-shared owner :codemirror-map)] 39 | (if (not= (:text (om/get-props owner)) 40 | (.getValue (@cm-map (:id opts)))) 41 | (.setValue 42 | (@cm-map (:id opts)) 43 | (:text (om/get-props owner)) 44 | )))) 45 | 46 | om/IDidMount 47 | (did-mount [_] 48 | (let [n (om/get-node owner "theInput")] 49 | (let [cm-map (om/get-shared owner :codemirror-map) 50 | cm 51 | (.fromTextArea 52 | js/CodeMirror 53 | n 54 | #js { 55 | :viewportMargin js/Infinity 56 | :matchBrackets true 57 | :lineNumbers false 58 | ;:mode "text/x-clojure" 59 | ;:keyMap "subpar" 60 | :extraKeys #js {"Shift-Enter" 61 | (shift-enter-fn owner (:loop-output-fn opts))} 62 | })] 63 | (swap! cm-map assoc (:id opts) cm) 64 | 65 | (.on 66 | cm 67 | "change" 68 | (fn [cm change] 69 | (om/transact! 70 | (om/get-props owner) 71 | [:text] 72 | (fn [e] (.getValue cm)))))))))) -------------------------------------------------------------------------------- /src/session/eval.cljs: -------------------------------------------------------------------------------- 1 | (ns session.eval 2 | (:require 3 | [cljs.js :as cljs])) 4 | 5 | 6 | (defn eval-str [env x] 7 | (cljs/eval-str 8 | env 9 | x 10 | nil 11 | {:eval cljs/js-eval 12 | :ns 'cljs.user 13 | :source-map true 14 | :context :expr 15 | ;:context :expr 16 | ;:def-emits-var true 17 | } 18 | (fn [{:keys [value error]}] 19 | (if (not error) 20 | value 21 | (println error))))) 22 | -------------------------------------------------------------------------------- /src/session/io.cljs: -------------------------------------------------------------------------------- 1 | (ns session.io 2 | (:require [goog.net.XhrIo :as xhr])) 3 | 4 | (defn session-get [session-base id callback] 5 | (xhr/send 6 | (str session-base id) 7 | callback 8 | "GET" 9 | "" 10 | #js {})) 11 | 12 | 13 | (defn session-put [service-url data callback] 14 | (xhr/send 15 | service-url 16 | callback 17 | "POST" 18 | (.stringify js/JSON #js {"edn" (pr-str data)}) 19 | #js {})) 20 | 21 | 22 | (comment 23 | (session-get 24 | "3153413548" 25 | (fn [x] (println (.getResponseText (.-target x))))) 26 | 27 | (session-put 28 | {:foo "foo"} 29 | (fn [x] (println (.getResponseText (.-target x))))) 30 | ) -------------------------------------------------------------------------------- /src/session/loop.cljs: -------------------------------------------------------------------------------- 1 | (ns session.loop 2 | (:require 3 | [om.core :as om] 4 | [om.dom :as dom] 5 | [session.editor :as editor])) 6 | 7 | 8 | 9 | 10 | (defn create-output [data owner] 11 | (reify om/IRender 12 | (render [_] 13 | (dom/div #js {:style #js {:padding-top "10px"}} (:text data))))) 14 | 15 | (defn create-loop [data owner] 16 | (reify om/IRender 17 | (render [_] 18 | (let [id (:id data) 19 | loop-output-fn 20 | (fn [x] 21 | ;(println "handler output") 22 | (om/transact! 23 | (om/get-props owner) 24 | [:output :text] 25 | (fn [e] x)))] 26 | (dom/div 27 | nil 28 | (dom/div 29 | nil 30 | (dom/input 31 | #js {:type "button" 32 | :value "insert" 33 | :style #js {:margin-top "20px" 34 | :margin-bottom "20px"} 35 | :onClick (fn [x] 36 | ((om/get-shared owner :loop-insert) 37 | id))}) 38 | ) 39 | 40 | 41 | (dom/div 42 | #js {:style #js {:display "flex" 43 | :alignItems "flex-start"}} 44 | (om/build 45 | editor/create-editor 46 | (:input data) 47 | {:opts 48 | {:id (:id data) 49 | :loop-output-fn 50 | loop-output-fn}}) 51 | (dom/input 52 | #js {:type "button" 53 | :value "eval" 54 | :style #js {:margin-left "5px"} 55 | :title "shortcut: shift+enter" 56 | :onClick (fn [x] 57 | (loop-output-fn 58 | (pr-str 59 | ((om/get-shared owner :eval) 60 | (:text (:input (om/get-props owner)))))))}) 61 | (dom/input 62 | #js {:type "button" 63 | :value "delete" 64 | :style #js {:margin-left "5px"} 65 | :onClick (fn [x] 66 | ((om/get-shared owner :loop-delete) 67 | id))})) 68 | (om/build create-output (:output data))))))) 69 | -------------------------------------------------------------------------------- /src/session/main.cljs: -------------------------------------------------------------------------------- 1 | (ns session.main 2 | (:require 3 | [session.system] 4 | [clojure.browser.repl :as repl] 5 | [session.app])) 6 | 7 | (enable-console-print!) 8 | 9 | ;(defonce conn (repl/connect "http://localhost:9000/repl")) 10 | 11 | 12 | (defn -main [] 13 | (let [s (session.system/system)] 14 | (let [h js/window.location.hash] 15 | (if 16 | (and (<= 11 (.-length h)) (= (subs h 0 11) "#/sessions/")) 17 | ((s :restore) (subs h 11 (.-length h))))) 18 | (session.app/main s "app") 19 | s)) 20 | 21 | (-main) 22 | 23 | (comment 24 | (def s (-main)) 25 | 26 | ((:loop-insert s) :last) 27 | ((:loop-insert s) "17518cea-6907-4eac-a1a9-46e901b2b202") 28 | 29 | ((:save s)) 30 | ((:restore s) "2671603389") 31 | 32 | ((:restore s) "2676795662") 33 | 34 | ;;2671603389 35 | 36 | js/window.location.pathname 37 | 38 | ) -------------------------------------------------------------------------------- /src/session/system.cljs: -------------------------------------------------------------------------------- 1 | (ns session.system 2 | (:require 3 | [om.core :as om] 4 | [om.dom :as dom] 5 | [session.io :as io] 6 | [cljs.reader :as reader] 7 | [cljs.js :as cljs] 8 | [session.eval] 9 | [cljs-uuid-utils.core :as uuid])) 10 | 11 | 12 | 13 | (defn save [service-url app-state] 14 | (let [x (update-in @app-state [:loops] (fn [x] (mapv #(dissoc % :output) x)))] 15 | (io/session-put 16 | service-url 17 | x 18 | (fn [y] 19 | (let [r (.getResponseText (.-target y)) 20 | id (:id 21 | (reader/read-string 22 | (reader/read-string r)))] 23 | ;(println r) 24 | (swap! 25 | app-state 26 | assoc 27 | :last-saved 28 | id) 29 | (set! js/window.location.hash (str "#/sessions/" id)) 30 | ))))) 31 | 32 | 33 | (defn restore [session-base-url state id] 34 | (let [x (io/session-get 35 | session-base-url 36 | id 37 | (fn [y] 38 | (reset! 39 | state 40 | (reader/read-string 41 | (.getResponseText (.-target y))))))] 42 | x)) 43 | 44 | 45 | (defn new-loop 46 | ([] (new-loop (uuid/uuid-string (uuid/make-random-uuid)))) 47 | ([uuid] 48 | {:id uuid :input {:text ""} :output {:text ""}})) 49 | 50 | 51 | (defn loop-insert [app-state id] 52 | (if (= id :last) 53 | (swap! app-state 54 | #(update-in 55 | % 56 | [:loops] 57 | (fn [loops] 58 | (conj loops (new-loop))))) 59 | (swap! app-state 60 | #(update-in 61 | % 62 | [:loops] 63 | (fn [loops] 64 | (let [x (split-with (fn [l] (not= id (:id l))) loops)] 65 | (vec 66 | (concat (first x) [(new-loop)] (last x))))))))) 67 | 68 | (defn loop-delete [app-state id] 69 | (swap! app-state 70 | #(update-in 71 | % 72 | [:loops] 73 | (fn [loops] 74 | (filterv (fn [l] (not= id (:id l))) loops))))) 75 | 76 | 77 | (defn system [] 78 | (let [env (cljs/empty-state) 79 | session-base-url "http://session-repl.com/sessions/" 80 | service-url "https://m06zrogt30.execute-api.us-east-1.amazonaws.com/prod/SessionService" 81 | app-state (atom {:loops [{:id "1" :input {:text ""} :output {:data ""}}]})] 82 | {:app-state app-state 83 | :session-base-url session-base-url 84 | :service-url service-url 85 | :compiler-state env 86 | :codemirror-map (atom {}) 87 | 88 | :eval (fn [x] (session.eval/eval-str env x)) 89 | :save (fn [] (save service-url app-state)) 90 | :restore (fn [x] 91 | (restore session-base-url app-state x)) 92 | :loop-insert #(loop-insert app-state %) 93 | :loop-delete #(loop-delete app-state %)})) 94 | 95 | 96 | -------------------------------------------------------------------------------- /test/session/core_test.clj: -------------------------------------------------------------------------------- 1 | (ns session.core-test 2 | (:require [clojure.test :refer :all] 3 | [session.core :refer :all])) 4 | 5 | (deftest a-test 6 | (testing "FIXME, I fail." 7 | (is (= 0 1)))) 8 | --------------------------------------------------------------------------------