├── .gitignore ├── LICENSE ├── README.md ├── cabal.project ├── default.nix ├── hadui ├── .gitignore ├── ChangeLog.md ├── LICENSE ├── README.md ├── Setup.hs ├── dev-main │ └── Main.hs ├── hadui.cabal ├── pub-main │ └── Main.hs ├── src │ ├── HaduiCfg.hs │ ├── HaduiDev.hs │ ├── HaduiMonad.hs │ ├── HaduiPub.hs │ ├── HaduiRT.hs │ ├── HaduiUtil.hs │ └── UIO.hs └── web │ ├── dev.html │ ├── dev.js │ ├── favicon.png │ ├── front.html │ ├── hadui-custom.css │ ├── hadui-custom.js │ ├── hadui.css │ ├── hadui.js │ ├── log.js │ ├── ts.js │ ├── vendor │ ├── cm │ │ ├── LICENSE │ │ ├── README.md │ │ ├── addon │ │ │ ├── comment │ │ │ │ ├── comment.js │ │ │ │ └── continuecomment.js │ │ │ ├── dialog │ │ │ │ ├── dialog.css │ │ │ │ └── dialog.js │ │ │ ├── edit │ │ │ │ ├── closebrackets.js │ │ │ │ ├── closetag.js │ │ │ │ ├── continuelist.js │ │ │ │ ├── matchbrackets.js │ │ │ │ ├── matchtags.js │ │ │ │ └── trailingspace.js │ │ │ ├── fold │ │ │ │ ├── brace-fold.js │ │ │ │ ├── comment-fold.js │ │ │ │ ├── foldcode.js │ │ │ │ ├── foldgutter.css │ │ │ │ ├── foldgutter.js │ │ │ │ ├── indent-fold.js │ │ │ │ ├── markdown-fold.js │ │ │ │ └── xml-fold.js │ │ │ ├── search │ │ │ │ ├── jump-to-line.js │ │ │ │ ├── match-highlighter.js │ │ │ │ ├── matchesonscrollbar.css │ │ │ │ ├── matchesonscrollbar.js │ │ │ │ ├── search.js │ │ │ │ └── searchcursor.js │ │ │ └── wrap │ │ │ │ └── hardwrap.js │ │ ├── keymap │ │ │ ├── emacs.js │ │ │ ├── sublime.js │ │ │ └── vim.js │ │ ├── lib │ │ │ ├── codemirror.css │ │ │ └── codemirror.js │ │ ├── mode │ │ │ └── haskell.js │ │ └── theme │ │ │ ├── elegant.css │ │ │ └── monokai.css │ ├── jquery │ │ └── jquery.js │ └── mui │ │ ├── LICENSE.txt │ │ ├── README.md │ │ ├── mui.min.css │ │ └── mui.min.js │ └── wsc.js ├── nixpkgs-overlays └── ghc865ife-overlay.nix ├── shell.nix └── stack.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.swp 3 | tarballs/ 4 | .stack-work/ 5 | stack.yaml.lock 6 | /dist/ 7 | /dist-newstyle/ 8 | result 9 | .ghc.environment* 10 | cabal.project.local 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2019, Compl Yue 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Web front UI for interactive Haskell projects 2 | 3 | [![Join the chat at https://gitter.im/hadui-web-front/community](https://badges.gitter.im/hadui-web-front/community.svg)](https://gitter.im/hadui-web-front/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 4 | 5 | ## Why Hadui 6 | 7 | > I had been faithful to use [CodeWorld](https://code.world/haskell) as the 8 | > workbench for my team, but to find out that it runs the program by the browser, 9 | > i.e. all in frontend, no backend. 10 | > 11 | > So comes Hadui - web UI to Haskell programs in backend. 12 | 13 | The idea behind Hadui is rather simple, just to use a web browser in 14 | place of the traditional terminal based console UI. Therefore, web 15 | technologies (HTML5/WebGL) based GUI & Visualization become native 16 | for Haskell programs. 17 | 18 | And for simplicity, it's achieved by having the web page (i.e. the 19 | frontend) keep life-long 20 | [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) 21 | connection with the process run in background (i.e. the backend), and use 22 | text packets for comm: 23 | 24 | - in order to control the representation state in browser, json command is 25 | sent from the backend Haskell program to web page for execution. 26 | 27 | - in responding to user interactions with the web page, Haskell code 28 | is sent from browser to backend process for execution. 29 | 30 | This is fundamentally not different than tradition IO approach to implement 31 | Terminal/Text UI for a 32 | [(emulated)](https://en.wikipedia.org/wiki/Terminal_emulator) 33 | [terminal](https://en.wikipedia.org/wiki/Computer_terminal) 34 | , only more flexible as it's inherently easier to extend the 35 | **json commands** (inplace of 36 | [ANSI Escape sequences](http://ascii-table.com/ansi-escape-sequences.php) 37 | ) and **Haskell statements** (inplace of 38 | [ASCII control characters](https://en.wiktionary.org/wiki/Appendix:Control_characters) 39 | ) compared to terminal based interactions via stdio, and not limited to one 40 | [tty](https://en.wikipedia.org/wiki/Text_terminal) 41 | per process - you can have many web pages open to interact with a single 42 | process. 43 | 44 | And a plus: binary packets/streams through the WebSocket can be used to 45 | communicate binary data efficiently between frontend and backend. 46 | 47 | ## Requirements 48 | 49 | With a rather small codebase, and the most extraordinary 50 | dependencies being 51 | [websockets](http://hackage.haskell.org/package/websockets) 52 | and 53 | [snap-server](http://hackage.haskell.org/package/snap-server) 54 | , Hadui is no more than a vanilla Haskell program (with 55 | [rio](http://hackage.haskell.org/package/rio) 56 | as the replacement Prelude if you care), actually you can hack it 57 | all the way you'd like. 58 | 59 | But for productivity, in composing vast Haskell pieces into 60 | an interactive context, with fast development iterations in mind, we 61 | choose to dynamicly compile & execute a Haskell project underlying. 62 | Therefore this 63 | [pending feature request for interactive frontend support in GHCi](https://gitlab.haskell.org/ghc/ghc/issues/17348) 64 | , it's not in stock GHC yet, now lives in 65 | [this experimental GHC branch](https://gitlab.haskell.org/complyue/ghc/tree/ghc-8.6-ife) 66 | as time being. Meaning you need a custom built GHC to use 67 | Hadui for now. 68 | 69 | Fortunately [Nix](https://nixos.org/nix) can save our asses in building 70 | GHC from source painlessly, at the mere cost of **several GBs** of disk 71 | space and one-shot build time of about **one hour** each GHC version. 72 | 73 | So besides the source available from its github repository, Hadui 74 | is only distributed via [Nixpkgs](https://nixos.org/nixpkgs/). 75 | 76 | Mind you that Nix is Linux focused, with decent support for macOS but 77 | Windows is not well supported. Much the same Hadui is. 78 | 79 | ## Quick Start 80 | 81 | [Install Nix](https://github.com/complyue/hadui/wiki/InstallNix) if not 82 | already. 83 | 84 | There're 3 flavors of Hadui project you can choose freely to start with, 85 | each with a scaffold template ready. To setup an interactive Haskell 86 | project with web UI: 87 | 88 | ### [Stack](https://haskellstack.org) based 89 | 90 | ```shell 91 | curl -L https://github.com/complyue/hadui-demo-stack/archive/master.tar.gz | tar xzf - 92 | mv hadui-demo-stack-master my-awsome-project 93 | cd my-awsome-project 94 | nix-shell --run 'stack build --exec hadui' 95 | ``` 96 | 97 | ### [Cabal](https://www.haskell.org/cabal) based 98 | 99 | ```shell 100 | curl -L https://github.com/complyue/hadui-demo-cabal/archive/master.tar.gz | tar xzf - 101 | mv hadui-demo-cabal-master my-awsome-project 102 | cd my-awsome-project 103 | nix-shell --run 'cabal v2-build all && hadui' 104 | ``` 105 | 106 | ### Barebone GHCi 107 | 108 | ```shell 109 | curl -L https://github.com/complyue/hadui-demo-nix/archive/master.tar.gz | tar xzf - 110 | mv hadui-demo-nix-master my-awsome-project 111 | cd my-awsome-project 112 | nix-shell --run hadui 113 | ``` 114 | 115 | ## Orientation 116 | 117 | Hadui is data science oriented, it is not suitable as a general purpose 118 | web framework. 119 | 120 | Artifacts from the underlying project are exposed to frontend in a flat 121 | name space. This is ideal to support analytical workflows, but overly 122 | open or even prohibitive to support business workflows. 123 | 124 | ## GHC versions 125 | 126 | The mod to add 127 | [interactive frontend support](https://gitlab.haskell.org/ghc/ghc/issues/17348) 128 | to GHC is very light - simply added `:frontend` cmd to allow a 129 | [Frontend plugin](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/extending_ghc.html#frontend-plugins) be used with GHCi. 130 | 131 | I would be maintaining custom branches matching the GHC version chosen 132 | by latest 133 | [LTS Haskell](https://www.stackage.org/lts) as well as 134 | [Nixpkgs](https://nixos.org/nixpkgs/), which is `8.6.5` 135 | at time of speaking. 136 | 137 | ## (My) Typical Usage 138 | 139 | > I believe Hadui can be useful in more ways for you and others, e.g. 140 | > a version of [CodeWorld](https://code.world) capable to leverage 141 | > the computing power of a computing center on the cloud. 142 | 143 | Data analysts use a browser to submit scripts (in native Haskell, for 144 | parameters, simple job control etc.) to trigger number crunching in 145 | the backend (a single Haskell process or a swarm of computing nodes), 146 | and to see results plotted back to the browser - more windows opened 147 | to show [Bokeh](https://bokeh.org) figures (with 148 | [Haze](https://github.com/complyue/haze) as a Hadui 149 | [overlay package](https://github.com/complyue/hadui/wiki/OverlayPackage) 150 | yet under construction). 151 | 152 | ![hadui-vscode-int-fe](https://user-images.githubusercontent.com/15646573/67581869-558f3f00-f77b-11e9-9e8a-c875a212c80b.png) 153 | 154 | Programmers have `hadui-dev` as the default build tool run an ever going 155 | build task in their [VSCode](https://code.visualstudio.com) environment 156 | with [HIE](https://github.com/haskell/haskell-ide-engine) enabled via 157 | [VsCode extension for Haskell](https://github.com/alanz/vscode-hie-server) 158 | , to develop crunching code in Haskell projects. 159 | 160 | ![hadui-vscode-int-be](https://user-images.githubusercontent.com/15646573/67583167-ab64e680-f77d-11e9-8574-4d71fd290a25.png) 161 | 162 | ## The UIO monad/module from package Hadui 163 | 164 | Haskell code from Hadui UI runs in the `UIO` monad. It's pretty much the 165 | same as `RIO` from the [rio](https://github.com/commercialhaskell/rio) 166 | library, with few addons like `print`/`uiLog`, and concrete `env` of type 167 | `UserInterfaceOutput`. It is essentially `ReaderT UserInterfaceOutput IO`, 168 | so you can do (un)lifting within it however you need. 169 | 170 | ```haskell 171 | -- | The monad for User Interface Output 172 | -- UIO is output only, conversely to IO (which stands for Input/Output), 173 | -- user inputs shall be facilitated with a registry of 'MVar's, 174 | -- those get filled with 'IoC' from UI widgets. 175 | newtype UIO a = UIO { unUIO :: ReaderT UserInterfaceOutput IO a } 176 | deriving (Functor, Applicative, Monad, MonadIO, 177 | MonadReader UserInterfaceOutput, MonadThrow) 178 | ``` 179 | 180 | After all, your code in the Haskell project has no necessarity to do with `UIO` at all, 181 | [print :: Display a => a -> UIO ()](https://github.com/complyue/hadui/blob/master/hadui/src/UIO.hs#L34) 182 | can give you a handful hand to show virtually any value to the log box in UI. 183 | (check out the 184 | [Display](https://www.stackage.org/haddock/lts/rio/RIO.html#t:Display) 185 | typeclass) And you can always do 186 | [liftIO](https://www.stackage.org/haddock/lts/base/Control-Monad-IO-Class.html#v:liftIO) 187 | or similar to obtain a value within a `do` block as necessary. 188 | 189 | And the `UIO` module re-exports 190 | [RIO](https://www.stackage.org/haddock/lts/rio/RIO.html) 191 | , so you can use it for 192 | [Prelude replacement](https://github.com/commercialhaskell/rio#prelude-replacement) 193 | as well as `RIO`. 194 | 195 | ## Demo 196 | 197 | After started the project you've created from any of the scaffolds as 198 | instructed above, open http://localhost:5050 199 | 200 | > Tip: there's development mode (run `hadui-dev` instead of `hadui`), where 201 | > you can just refresh the browser page after source modification in the project, 202 | > the backend process will be restarted, and changed source will be recompiled 203 | > automatically. 204 | 205 | ![hadui-demo-fe](https://user-images.githubusercontent.com/15646573/70150770-7dac7f00-16e5-11ea-9b79-59b52d4efab0.png) 206 | ![hadui-demo-be](https://user-images.githubusercontent.com/15646573/70150766-7dac7f00-16e5-11ea-9114-711c5ce32ca5.png) 207 | 208 | - you customize front UI for your project, by having a 209 | `hadui` folder besides `hadui.yaml` under the project root. 210 | 211 | take for example: 212 | https://github.com/complyue/hadui-demo-stack/tree/master/hadui 213 | 214 | - the [Rating.hs module](https://github.com/complyue/hadui-demo-stack/blob/master/hadui-demo/src/Rating.hs) 215 | is paired with [rating.html page](https://github.com/complyue/hadui-demo-stack/blob/master/hadui/rating.html) to use state in frontend only. 216 | ![hadui-rating](https://user-images.githubusercontent.com/15646573/67364542-54ef8080-f5a2-11e9-946f-b4c88cfd8177.png) 217 | 218 | - the [StatefulRating.hs module](https://github.com/complyue/hadui-demo-stack/blob/master/hadui-demo/src/StatefulRating.hs) 219 | is paired with [stateful-rating.html page](https://github.com/complyue/hadui-demo-stack/blob/master/hadui/stateful-rating.html) to use state in backend. 220 | ![hadui-stateful-rating](https://user-images.githubusercontent.com/15646573/67364543-55881700-f5a2-11e9-9499-10a488e2c818.png) 221 | 222 | - the [updateRank js method](https://github.com/complyue/hadui-demo-stack/blob/master/hadui/hadui-custom.js#L41) is shared by above 2 examples to update UI from Haskell code. 223 | 224 | - wanna your own front page ? 225 | 226 | just create `hadui/front.html` under your project root. 227 | 228 | > all resources under https://github.com/complyue/hadui/tree/master/hadui/web 229 | > can be preceded by placing a same named file under your project's `hadui` 230 | > folder. there be `front.html` of just symlink to `dev.html`, with your own 231 | > front page inplace, you can still access the good old dev page at: 232 | > http://localhost:5050/dev.html 233 | 234 | ## VSCode Integration 235 | 236 | Setup your [VSCode](https://code.visualstudio.com) environment 237 | with [HIE](https://github.com/haskell/haskell-ide-engine) enabled via 238 | [VsCode extension for Haskell](https://github.com/alanz/vscode-hie-server) 239 | 240 | Just open with VSCode the project you've created from one of the scaffold 241 | templates above, there's already `.vscode/tasks.json` from the scaffold with 242 | following contents: 243 | 244 | ```json 245 | { 246 | "version": "2.0.0", 247 | "presentation": { 248 | "reveal": "always", 249 | "panel": "new" 250 | }, 251 | "tasks": [ 252 | { 253 | "group": { 254 | "kind": "build", 255 | "isDefault": true 256 | }, 257 | "label": "hadui-dev", 258 | "type": "shell", 259 | "command": "cd ${workspaceRoot}; nix-shell --run hadui-dev" 260 | } 261 | ] 262 | } 263 | ``` 264 | 265 | Press `F7` (macOS) or `Ctrl+Shift+B` (Linux) to start `hadui-dev` for the project 266 | 267 | ![hadui-vscode](https://user-images.githubusercontent.com/15646573/67378020-26c96b00-f5b9-11e9-9780-302db88ff50d.png) 268 | 269 | ## Debugging with VSCode 270 | 271 | coming sooner than later ... 272 | -------------------------------------------------------------------------------- /cabal.project: -------------------------------------------------------------------------------- 1 | 2 | packages: */*.cabal 3 | -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | # This is Nix expression for Hadui the project, exposing 2 | # an overlaid nixpkgs with a new Haskell package set armed 3 | # as the standard (i.e. `haskellPackages`), the package set 4 | # includes Hadui the package (i.e. `haskellPackages.hadui`), 5 | # and Hadui the package is added to top-level as well. 6 | # 7 | # You'd install Hadui the tool with: 8 | # 9 | # nix-env -iA hadui -f https://github.com/complyue/hadui/archive/0.1.0.0.tar.gz 10 | # 11 | { overlays ? [], ... }@args: 12 | let 13 | haduiOverlay = self: super: 14 | let 15 | hpsWithHadui = super.haskellPackages.override { 16 | overrides = hself: hsuper: { 17 | hadui = hself.callCabal2nix "hadui" ./hadui {}; 18 | }; 19 | }; 20 | in { 21 | # the top-level Nix package for Hadui 22 | hadui = hpsWithHadui.hadui; 23 | # override the Haskell package set at standard locations 24 | haskellPackages = hpsWithHadui; 25 | haskell = super.haskell // { 26 | packages = super.haskell.packages // { ghcWithHadui = hpsWithHadui; }; 27 | }; 28 | }; 29 | in import (args // { 30 | overlays = [ 31 | # this overlay creates & sets-default a new Haskell package 32 | # set (i.e. `haskellPackages`), with the experimental GHC 33 | # with interactive frontend support, which is mandatory 34 | # for Hadui to function. 35 | (import ./nixpkgs-overlays/ghc865ife-overlay.nix) 36 | 37 | # this overlay as defined above overrides & sets-default 38 | # a new Haskell package set with Hadui the package (i.e. 39 | # `haskellPackages.hadui`) included. Hadui the package 40 | # is also made available at top-level of nixpkgs. 41 | haduiOverlay 42 | ] ++ overlays; 43 | }) 44 | -------------------------------------------------------------------------------- /hadui/.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.swp 3 | tarballs/ 4 | .stack-work/ 5 | stack.yaml.lock 6 | /dist/ 7 | /dist-newstyle/ 8 | result 9 | .ghc.environment* 10 | cabal.project.local 11 | -------------------------------------------------------------------------------- /hadui/ChangeLog.md: -------------------------------------------------------------------------------- 1 | # Changelog for Hadui 2 | 3 | ## 0.1.0.1 Experimental Release 4 | first unregistered (to Hackage) release. 5 | 6 | ## 0.1.0.2 Experimental Release 7 | fix version numbers around. 8 | 9 | ## Unreleased changes 10 | -------------------------------------------------------------------------------- /hadui/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Compl (c) 2019 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above 12 | copyright notice, this list of conditions and the following 13 | disclaimer in the documentation and/or other materials provided 14 | with the distribution. 15 | 16 | * Neither the name of Compl nor the names of other 17 | contributors may be used to endorse or promote products derived 18 | from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE 2019 Compl HOLDERS AND CONTRIBUTORS 21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 2019 Compl 24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /hadui/README.md: -------------------------------------------------------------------------------- 1 | # Web front UI for interactive Haskell projects 2 | -------------------------------------------------------------------------------- /hadui/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /hadui/dev-main/Main.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE NoImplicitPrelude #-} 2 | {-# LANGUAGE OverloadedStrings #-} 3 | {-# LANGUAGE ScopedTypeVariables #-} 4 | {-# LANGUAGE BlockArguments #-} 5 | {-# LANGUAGE LambdaCase #-} 6 | {-# LANGUAGE BangPatterns #-} 7 | 8 | module Main 9 | ( main 10 | ) 11 | where 12 | 13 | import RIO 14 | import RIO.FilePath 15 | 16 | 17 | import qualified System.Directory as D 18 | import UnliftIO.Concurrent 19 | 20 | import Network.Socket 21 | 22 | import System.Posix.Types 23 | import System.Posix.Process 24 | import System.Posix.IO 25 | 26 | import HaduiCfg 27 | import HaduiRT 28 | 29 | import qualified Paths_hadui as Meta 30 | 31 | 32 | main :: IO () 33 | main = do 34 | prj <- loadHaduiConfig 35 | 36 | dataDir <- Meta.getDataDir 37 | let haduiResRoot = dataDir "web" 38 | D.doesDirectoryExist haduiResRoot >>= \case 39 | True -> return () 40 | _ -> error "Hadui web resource directory missing ?!" 41 | 42 | let !cfg = haduiCfg prj 43 | lo <- haduiBackendLogOpts cfg 44 | withLogFunc lo $ \lf -> 45 | let devApp = HaduiDevServer { haduiProjectRoot = projectRoot prj 46 | , haduiPrj = prj 47 | , haduiDevLogFunc = lf 48 | } 49 | in runRIO devApp $ runDevServer haduiResRoot 50 | 51 | data HaduiDevServer = HaduiDevServer { 52 | haduiProjectRoot :: FilePath 53 | , haduiPrj :: !HaduiProject 54 | , haduiDevLogFunc :: !LogFunc 55 | } 56 | 57 | instance HasLogFunc HaduiDevServer where 58 | logFuncL = lens haduiDevLogFunc (\x y -> x { haduiDevLogFunc = y }) 59 | 60 | 61 | runDevServer :: FilePath -> RIO HaduiDevServer () 62 | runDevServer haduiResRoot = do 63 | devs <- ask 64 | let !prj = haduiPrj devs 65 | !cfg = haduiCfg prj 66 | 67 | logDebug $ "Hadui using resource dir: [" <> fromString haduiResRoot <> "]" 68 | logInfo 69 | $ "Hadui developing project at [" 70 | <> fromString (haduiProjectRoot devs) 71 | <> "]" 72 | 73 | let 74 | upstartHandler conn = do 75 | -- this works with network-2.x 76 | let wsfd = fdSocket conn 77 | -- following works with network-3.x 78 | -- wsfd <- unsafeFdSocket conn 79 | 80 | -- clear FD_CLOEXEC flag so it can be passed to subprocess 81 | setFdOption (Fd wsfd) CloseOnExec False 82 | 83 | -- launch `stack ghci` with hadui's GHC frontend to serve the ws 84 | pid <- forkProcess $ executeFile 85 | "/usr/bin/env" 86 | False 87 | (haduiGHCiCmdl prj "HaduiDev" [show wsfd]) 88 | Nothing 89 | 90 | runRIO devs 91 | $ logDebug 92 | $ display 93 | $ "Hadui started dev process pid: " 94 | <> tshow pid 95 | 96 | -- say sth on exit of the subprocess, this also prevents 97 | -- the exited subprocess becoming a zombie. 98 | void $ forkIO $ do 99 | ps <- getProcessStatus True True pid 100 | void $ runRIO devs $ case ps of 101 | Nothing -> error "the impossible happens here" 102 | Just (Exited ExitSuccess) -> 103 | logDebug 104 | $ display 105 | $ "Hadui dev process " 106 | <> tshow pid 107 | <> " exited." 108 | Just (Exited exitCode) -> 109 | logError 110 | $ display 111 | $ "Hadui dev process " 112 | <> tshow pid 113 | <> " exited with " 114 | <> tshow exitCode 115 | Just (Terminated sig coreDumped) -> 116 | logWarn 117 | $ display 118 | $ "Hadui dev process " 119 | <> tshow pid 120 | <> " killed by signal " 121 | <> tshow sig 122 | <> if coreDumped then " with core dumped" else "" 123 | Just (Stopped sig) -> 124 | logWarn 125 | $ display 126 | $ "Hadui dev process " 127 | <> tshow pid 128 | <> " stopped by signal " 129 | <> tshow sig 130 | 131 | -- serve websockets in background threads 132 | let closeFdInParent conn = do 133 | -- this works with network-2.x 134 | let wsfd = fdSocket conn 135 | -- following works with network-3.x 136 | -- wsfd <- unsafeFdSocket conn 137 | 138 | -- always close the fd of socket in parent process, the socket 139 | -- will be shutdown when no fd kept open on it. 140 | -- the subprocess will hold the inherited fd open until it exits, 141 | -- and if no subprocess launched successfully, the socket will 142 | -- be shutdown righ away as the only fd in the parent process is 143 | -- closed here. 144 | closeFd $ Fd wsfd 145 | haduiListenWSC cfg closeFdInParent upstartHandler 146 | 147 | -- continue to serve http in main thread 148 | haduiServeHttp cfg (haduiProjectRoot devs) haduiResRoot 149 | 150 | -------------------------------------------------------------------------------- /hadui/hadui.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: 2.4 2 | 3 | name: hadui 4 | version: 0.1.0.2 5 | license: BSD-3-Clause 6 | license-file: LICENSE 7 | copyright: 2019 Compl Yue 8 | maintainer: compl.yue@icloud.com 9 | author: Compl Yue 10 | stability: experimental 11 | homepage: https://github.com/complyue/hadui 12 | bug-reports: https://github.com/complyue/hadui/issues 13 | synopsis: Web front UI for interactive Haskell projects 14 | description: 15 | Please see the README on Github at 16 | 17 | category: Interactive,Development,Web,UI 18 | build-type: Simple 19 | data-files: 20 | -- while Cabal 3.0.0.0 does it well, 21 | -- unfortunately Cabal 2.4.0.1 bundled with GHC 8.6.5 fails 22 | -- handling double star wildcards like this, 23 | -- web/**/*.html 24 | -- web/**/*.js 25 | -- web/**/*.css 26 | -- web/**/*.png 27 | -- as Nix builds by compiling `Setup.hs` directly against 28 | -- GHC's core Cabal library, we have to explicitly list 29 | -- all files like this by far. 30 | web/front.html 31 | web/hadui-custom.js 32 | web/log.js 33 | web/wsc.js 34 | web/hadui.css 35 | web/dev.html 36 | web/hadui-custom.css 37 | web/favicon.png 38 | web/dev.js 39 | web/hadui.js 40 | web/ts.js 41 | web/vendor/jquery/jquery.js 42 | web/vendor/mui/mui.min.js 43 | web/vendor/mui/README.md 44 | web/vendor/mui/mui.min.css 45 | web/vendor/cm/mode/haskell.js 46 | web/vendor/cm/theme/elegant.css 47 | web/vendor/cm/theme/monokai.css 48 | web/vendor/cm/keymap/sublime.js 49 | web/vendor/cm/keymap/emacs.js 50 | web/vendor/cm/keymap/vim.js 51 | web/vendor/cm/lib/codemirror.js 52 | web/vendor/cm/lib/codemirror.css 53 | web/vendor/cm/addon/comment/continuecomment.js 54 | web/vendor/cm/addon/comment/comment.js 55 | web/vendor/cm/addon/search/matchesonscrollbar.js 56 | web/vendor/cm/addon/search/jump-to-line.js 57 | web/vendor/cm/addon/search/match-highlighter.js 58 | web/vendor/cm/addon/search/searchcursor.js 59 | web/vendor/cm/addon/search/search.js 60 | web/vendor/cm/addon/search/matchesonscrollbar.css 61 | web/vendor/cm/addon/dialog/dialog.js 62 | web/vendor/cm/addon/dialog/dialog.css 63 | web/vendor/cm/addon/edit/continuelist.js 64 | web/vendor/cm/addon/edit/closetag.js 65 | web/vendor/cm/addon/edit/matchtags.js 66 | web/vendor/cm/addon/edit/closebrackets.js 67 | web/vendor/cm/addon/edit/matchbrackets.js 68 | web/vendor/cm/addon/edit/trailingspace.js 69 | web/vendor/cm/addon/wrap/hardwrap.js 70 | web/vendor/cm/addon/fold/xml-fold.js 71 | web/vendor/cm/addon/fold/foldgutter.js 72 | web/vendor/cm/addon/fold/brace-fold.js 73 | web/vendor/cm/addon/fold/comment-fold.js 74 | web/vendor/cm/addon/fold/foldgutter.css 75 | web/vendor/cm/addon/fold/markdown-fold.js 76 | web/vendor/cm/addon/fold/foldcode.js 77 | web/vendor/cm/addon/fold/indent-fold.js 78 | 79 | extra-source-files: 80 | README.md 81 | ChangeLog.md 82 | 83 | source-repository head 84 | type: git 85 | location: https://github.com/complyue/hadui 86 | branch: stable 87 | subdir: hadui 88 | 89 | common shared-properties 90 | default-language: Haskell2010 91 | build-depends: 92 | ghc >=8.6, 93 | base >=4.12 && <5.0, 94 | 95 | unix -any, 96 | process -any, 97 | -- TODO upgrade to 3.x after Stack LTS does 98 | network >=2.8 && <3.0, 99 | websockets -any, 100 | snap-core -any, 101 | snap-server -any, 102 | -- TODO use acceleratehs array compatible blob types 103 | vector -any, 104 | 105 | rio -any, 106 | text -any, 107 | bytestring -any, 108 | directory -any, 109 | HsYAML -any, 110 | aeson -any, 111 | aeson-qq -any 112 | ghc-options: 113 | -Wall -Wcompat -Widentities -Wincomplete-record-updates 114 | -Wincomplete-uni-patterns -Wpartial-fields -Wredundant-constraints 115 | 116 | common surface-properties 117 | other-modules: 118 | Paths_hadui 119 | 120 | library hadui-internal 121 | import: shared-properties 122 | hs-source-dirs: src 123 | exposed-modules: 124 | UIO 125 | HaduiMonad 126 | HaduiUtil 127 | HaduiRT 128 | HaduiCfg 129 | HaduiDev 130 | HaduiPub 131 | Paths_hadui 132 | autogen-modules: 133 | Paths_hadui 134 | 135 | library 136 | import: shared-properties 137 | import: surface-properties 138 | build-depends: hadui-internal 139 | reexported-modules: 140 | UIO, 141 | HaduiUtil, 142 | HaduiMonad, 143 | HaduiCfg, 144 | HaduiRT, 145 | -- entry modules of GHC frontend plugin need to be exposed 146 | HaduiDev, 147 | HaduiPub, 148 | 149 | executable hadui 150 | import: shared-properties 151 | import: surface-properties 152 | build-depends: hadui-internal 153 | main-is: Main.hs 154 | hs-source-dirs: pub-main 155 | ghc-options: 156 | -- in publication mode, the `hadui` executable is just a 157 | -- thin wrapper to launch `stack ghci` with 'HaduiPub' as 158 | -- the interactive GHC frontend. 159 | -- but more than 1 native threads could help avoiding quirks 160 | -- in single-threaded cooperative scheduling. 161 | -threaded -rtsopts -with-rtsopts=-maxN2 162 | 163 | executable hadui-dev 164 | import: shared-properties 165 | import: surface-properties 166 | build-depends: hadui-internal 167 | main-is: Main.hs 168 | hs-source-dirs: dev-main 169 | ghc-options: 170 | -- in development mode, the hadui process only handles light 171 | -- http traffics, no need of much parallelism. 172 | -- but more than 1 native threads could help avoiding quirks 173 | -- in single-threaded cooperative scheduling. 174 | -threaded -rtsopts -with-rtsopts=-maxN2 175 | -------------------------------------------------------------------------------- /hadui/pub-main/Main.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE NoImplicitPrelude #-} 2 | {-# LANGUAGE OverloadedStrings #-} 3 | 4 | module Main 5 | ( main 6 | ) 7 | where 8 | 9 | import RIO 10 | 11 | import System.Posix.Process 12 | 13 | import HaduiCfg 14 | 15 | 16 | main :: IO () 17 | main = do 18 | prj <- loadHaduiConfig 19 | 20 | executeFile "/usr/bin/env" False (haduiGHCiCmdl prj "HaduiPub" []) Nothing 21 | -------------------------------------------------------------------------------- /hadui/src/HaduiCfg.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE NoImplicitPrelude #-} 2 | {-# LANGUAGE OverloadedStrings #-} 3 | {-# LANGUAGE ScopedTypeVariables #-} 4 | {-# LANGUAGE PartialTypeSignatures #-} 5 | {-# LANGUAGE BlockArguments #-} 6 | {-# LANGUAGE RankNTypes #-} 7 | {-# LANGUAGE FlexibleContexts #-} 8 | {-# LANGUAGE ExistentialQuantification #-} 9 | {-# LANGUAGE MultiParamTypeClasses #-} 10 | {-# LANGUAGE FlexibleInstances #-} 11 | {-# LANGUAGE TypeFamilies #-} 12 | {-# LANGUAGE UndecidableInstances #-} 13 | {-# LANGUAGE BangPatterns #-} 14 | {-# LANGUAGE LambdaCase #-} 15 | {-# LANGUAGE QuasiQuotes #-} 16 | 17 | -- | hadui configuration 18 | module HaduiCfg 19 | ( HaduiProject(..) 20 | , HaduiConfig(..) 21 | , loadHaduiConfig 22 | , resolveHaduiResRoots 23 | , haduiBackendLogOpts 24 | , haduiGHCiCmdl 25 | ) 26 | where 27 | 28 | import RIO 29 | import qualified RIO.Text as T 30 | import qualified RIO.ByteString.Lazy as BL 31 | import RIO.FilePath 32 | 33 | import qualified System.Directory as D 34 | import System.Process 35 | 36 | import Data.YAML 37 | 38 | 39 | findHaduiPrjRoot :: IO (Maybe (FilePath, FilePath)) 40 | findHaduiPrjRoot = D.getCurrentDirectory >>= searchPrjRoot where 41 | searchPrjRoot :: FilePath -> IO (Maybe (FilePath, FilePath)) 42 | searchPrjRoot d = 43 | let yamlFile = d "hadui.yaml" 44 | in D.doesFileExist yamlFile >>= \case 45 | True -> return $ Just (normalise d, yamlFile) 46 | False -> 47 | let pd = takeDirectory d 48 | in if pd == d -- reached filesystem root 49 | then return Nothing 50 | else searchPrjRoot pd 51 | 52 | loadHaduiConfig :: IO HaduiProject 53 | loadHaduiConfig = findHaduiPrjRoot >>= \case 54 | Nothing -> 55 | error "Can not locate Hadui project root, forget to create 'hadui.yaml' ?" 56 | Just (prjRoot, haduiYamlFile) -> do 57 | hasBarePrj <- D.doesFileExist $ prjRoot ".ghci" 58 | hasCabalPrj <- D.doesFileExist $ prjRoot "cabal.project" 59 | hasStackPrj <- D.doesFileExist $ prjRoot "stack.yaml" 60 | if not (hasBarePrj || hasCabalPrj || hasStackPrj) 61 | then 62 | error 63 | $ "Please define the type of your Hadui project by crafting one of [stack.yaml/cabal.project/.ghci] in dir [" 64 | <> prjRoot 65 | <> "]" 66 | else 67 | (withBinaryFile haduiYamlFile ReadMode $ \h -> do 68 | bytes <- BL.hGetContents h 69 | return $! decode1 bytes 70 | ) 71 | >>= \case 72 | Left yamlErr -> 73 | error $ "Error with hadui.yaml " <> (show yamlErr) 74 | Right cfg -> return $ HaduiProject prjRoot 75 | hasBarePrj 76 | hasCabalPrj 77 | hasStackPrj 78 | cfg 79 | 80 | 81 | resolveHaduiResRoots :: [Text] -> IO [FilePath] 82 | resolveHaduiResRoots = mapM $ \pkg -> 83 | readProcessWithExitCode 84 | "/usr/bin/env" 85 | ["ghc-pkg", "field", "--simple-output", T.unpack (pkg), "data-dir"] 86 | "" 87 | >>= \case 88 | (ExitSuccess, outBytes, "") -> 89 | let pkgDataDir = (T.unpack . T.strip . T.pack) outBytes 90 | in return $ pkgDataDir "web" 91 | (exitCode, out, err) -> 92 | error 93 | $ "Failed locating data-dir for package [" 94 | <> T.unpack pkg 95 | <> "], " 96 | <> show exitCode 97 | <> "\n" 98 | <> err 99 | <> "\n" 100 | <> out 101 | 102 | 103 | data HaduiProject = HaduiProject { 104 | projectRoot :: FilePath 105 | , hasBareProject :: Bool 106 | , hasCabalProject :: Bool 107 | , hasStackProject :: Bool 108 | , haduiCfg :: HaduiConfig 109 | } deriving (Eq,Show ) 110 | 111 | data HaduiConfig = HaduiConfig { 112 | bindInterface :: Text 113 | , httpPort :: Int 114 | , wsPort :: Int 115 | , logLevel :: Text 116 | , overlayPackages ::[Text] 117 | , ghciTargets :: [Text] 118 | , ghciOptions :: [Text] 119 | , ghcOptions :: [Text] 120 | } deriving (Eq,Show ) 121 | 122 | instance FromYAML HaduiConfig where 123 | parseYAML = withMap "HaduiConfig" $ \v -> 124 | HaduiConfig 125 | <$> v 126 | .:? "bind-interface" 127 | .!= "127.0.0.1" 128 | <*> v 129 | .:? "http-port" 130 | .!= 5050 131 | <*> v 132 | .:? "ws-port" 133 | .!= 5051 134 | <*> v 135 | .:? "log-level" 136 | .!= "INFO" 137 | <*> v 138 | .:? "overlay" 139 | .!= [] 140 | <*> v 141 | .:? "ghci-targets" 142 | .!= [] 143 | <*> v 144 | .:? "ghci-options" 145 | .!= [] 146 | <*> v 147 | .:? "ghc-options" 148 | .!= [] 149 | 150 | 151 | haduiBackendLogOpts :: HaduiConfig -> IO LogOptions 152 | haduiBackendLogOpts cfg = do 153 | let ll = case logLevel cfg of 154 | "DEBUG" -> LevelDebug 155 | "WARN" -> LevelWarn 156 | "ERROR" -> LevelError 157 | _ -> LevelInfo 158 | verbose = ll < LevelWarn -- go verbose since info level 159 | lo <- logOptionsHandle stderr verbose 160 | return $ setLogMinLevel ll lo 161 | 162 | 163 | -- Stack tries to load all components from the underlying Haskell 164 | -- project into GHCi by default, while cabal-install mandatory the 165 | -- user to specify the target explicitly, so wrt ease of use, 166 | -- we prefer Stack over Cabal here, as we are more application 167 | -- oriented than library oriented. assuming those library users 168 | -- who favor Cabal over Stack will not have `stack.yaml` defined 169 | -- for the interactive Hadui project, or even without 170 | -- `cabal.project` defined, they should enjoy crafting a `.ghci` 171 | -- script to control behavior of GHCi. 172 | -- 173 | -- see: https://github.com/haskell/cabal/issues/5374 174 | haduiGHCiCmdl :: HaduiProject -> String -> [String] -> [String] 175 | haduiGHCiCmdl prj fePluginName feArgs = 176 | -- the cmdl allowing copy&paste to bash prompt 177 | -- trace 178 | -- ( "# --- begin Hadui cmdl ---\n" 179 | -- <> T.pack (unwords [ "'" <> o <> "'" | o <- cmdl ]) 180 | -- <> "\n# === end Hadui cmdl ===" 181 | -- ) 182 | cmdl where 183 | !cfg = haduiCfg prj 184 | !cmdl = if (hasStackProject prj) 185 | then 186 | -- Stack based project 187 | ["stack", "ghci"] 188 | ++ [ 189 | 190 | -- TODO stack will ask through the tty if multiple executables 191 | -- are defined in the project, Hadui won't play well in this 192 | -- case. file an issue with stack, maybe introduce a new cmdl 193 | -- option to load all library modules with no question asked. 194 | 195 | -- use UIO which reexports RIO as prelude 196 | "--ghc-options" 197 | , "-XNoImplicitPrelude" 198 | 199 | -- really hope that Haskell the language unify the string 200 | -- types (with utf8 seems the norm) sooner than later 201 | , "--ghc-options" 202 | , "-XOverloadedStrings" 203 | 204 | -- to allow literal Text/Int without explicit type anno 205 | , "--ghc-options" 206 | , "-XExtendedDefaultRules" 207 | 208 | -- to stop on uncaught errors 209 | , "--ghci-options" 210 | , "-fbreak-on-error" 211 | 212 | -- the frontend trigger 213 | , "--ghci-options" 214 | , "-e \":frontend " ++ fePluginName ++ "\"" 215 | ] 216 | ++ ( concat 217 | $ [ ["--ghci-options", "-ffrontend-opt " ++ fea] | fea <- feArgs ] 218 | ++ [ ["--ghci-options", T.unpack opt] | opt <- ghciOptions cfg ] 219 | ++ [ ["--ghc-options", T.unpack opt] | opt <- ghcOptions cfg ] 220 | ) 221 | ++ (map T.unpack $ ghciTargets cfg) 222 | else if (hasCabalProject prj) 223 | then 224 | -- Cabal based project 225 | ["cabal", "v2-repl"] 226 | ++ [ 227 | 228 | -- TODO stack will ask through the tty if multiple executables 229 | -- are defined in the project, Hadui won't play well in this 230 | -- case. file an issue with stack, maybe introduce a new cmdl 231 | -- option to load all library modules with no question asked. 232 | 233 | -- use UIO which reexports RIO as prelude 234 | "--repl-options" 235 | , "-XNoImplicitPrelude" 236 | 237 | -- really hope that Haskell the language unify the string 238 | -- types (with utf8 seems the norm) sooner than later 239 | , "--repl-options" 240 | , "-XOverloadedStrings" 241 | 242 | -- to allow literal Text/Int without explicit type anno 243 | , "--repl-options" 244 | , "-XExtendedDefaultRules" 245 | 246 | -- to stop on uncaught errors 247 | , "--repl-options" 248 | , "-fbreak-on-error" 249 | 250 | -- the frontend trigger 251 | , "--repl-options" 252 | , "-e" 253 | , "--repl-options" 254 | , ":frontend " ++ fePluginName 255 | ] 256 | ++ ( concat 257 | $ [ ["--repl-options", "-ffrontend-opt " ++ fea] | fea <- feArgs ] 258 | ++ [ ["--repl-options", T.unpack opt] | opt <- ghciOptions cfg ] 259 | ++ [ ["--repl-options", T.unpack opt] | opt <- ghcOptions cfg ] 260 | ) 261 | ++ (map T.unpack $ ghciTargets cfg) 262 | else 263 | -- barebone project 264 | [ "ghci" 265 | 266 | -- make available hadui the package to GHCi 267 | , "-package" 268 | , "hadui" 269 | 270 | -- use UIO which reexports RIO as prelude 271 | , "-XNoImplicitPrelude" 272 | 273 | -- really hope that Haskell the language unify the string 274 | -- types (with utf8 seems the norm) sooner than later 275 | , "-XOverloadedStrings" 276 | 277 | -- to allow literal Text/Int without explicit type anno 278 | , "-XExtendedDefaultRules" 279 | 280 | -- to stop on uncaught errors 281 | , "-fbreak-on-error" 282 | 283 | -- the frontend trigger 284 | , "-e" 285 | , ":frontend " ++ fePluginName 286 | ] 287 | ++ concat [ ["-ffrontend-opt", fea] | fea <- feArgs ] 288 | ++ [ T.unpack opt | opt <- ghciOptions cfg ] 289 | ++ [ T.unpack opt | opt <- ghcOptions cfg ] 290 | 291 | -------------------------------------------------------------------------------- /hadui/src/HaduiDev.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE NoImplicitPrelude #-} 2 | {-# LANGUAGE OverloadedStrings #-} 3 | {-# LANGUAGE ScopedTypeVariables #-} 4 | {-# LANGUAGE PartialTypeSignatures #-} 5 | {-# LANGUAGE BlockArguments #-} 6 | {-# LANGUAGE RankNTypes #-} 7 | {-# LANGUAGE FlexibleContexts #-} 8 | {-# LANGUAGE ExistentialQuantification #-} 9 | {-# LANGUAGE MultiParamTypeClasses #-} 10 | {-# LANGUAGE FlexibleInstances #-} 11 | {-# LANGUAGE TypeFamilies #-} 12 | {-# LANGUAGE UndecidableInstances #-} 13 | {-# LANGUAGE BangPatterns #-} 14 | 15 | module HaduiDev 16 | ( frontendPlugin 17 | ) 18 | where 19 | 20 | import RIO 21 | 22 | import GHC 23 | import Panic 24 | import GhcPlugins 25 | 26 | import HaduiRT 27 | 28 | 29 | frontendPlugin :: FrontendPlugin 30 | frontendPlugin = defaultFrontendPlugin { frontend = gfeMain } where 31 | -- GHC frontend plugin entry point 32 | gfeMain flags args = do 33 | unless (null args) $ throwGhcException $ CmdLineError 34 | "HaduiDev expects NO src" 35 | case flags of 36 | [wsfdStr] -> case (readMaybe wsfdStr :: Maybe Int) of 37 | Nothing -> throwGhcException $ CmdLineError "Invalid wsfd" 38 | Just wsfd -> haduiDevServer wsfd 39 | _ -> throwGhcException 40 | $ CmdLineError "HaduiDev expects single wsfd as arg" 41 | 42 | -------------------------------------------------------------------------------- /hadui/src/HaduiMonad.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE NoImplicitPrelude #-} 2 | {-# LANGUAGE OverloadedStrings #-} 3 | {-# LANGUAGE ScopedTypeVariables #-} 4 | {-# LANGUAGE PartialTypeSignatures #-} 5 | {-# LANGUAGE BlockArguments #-} 6 | {-# LANGUAGE RankNTypes #-} 7 | {-# LANGUAGE GeneralizedNewtypeDeriving #-} 8 | {-# LANGUAGE FlexibleContexts #-} 9 | {-# LANGUAGE ExistentialQuantification #-} 10 | {-# LANGUAGE MultiParamTypeClasses #-} 11 | {-# LANGUAGE FlexibleInstances #-} 12 | {-# LANGUAGE TypeFamilies #-} 13 | {-# LANGUAGE UndecidableInstances #-} 14 | {-# LANGUAGE BangPatterns #-} 15 | {-# LANGUAGE LambdaCase #-} 16 | {-# LANGUAGE QuasiQuotes #-} 17 | 18 | -- | Hadui runtime 19 | module HaduiMonad 20 | ( UIO(..) 21 | , UserInterfaceOutput(..) 22 | , runUIO 23 | , mustUIO 24 | , initUIO 25 | , withHaduiFront 26 | ) 27 | where 28 | 29 | import RIO 30 | 31 | import System.IO.Unsafe 32 | import Data.Dynamic ( Dynamic(..) ) 33 | 34 | import qualified GHC 35 | import qualified GhcMonad as GHC 36 | 37 | import qualified Network.WebSockets as WS 38 | 39 | import HaduiCfg 40 | 41 | 42 | -- | The monad for User Interface Output 43 | -- UIO is output only, conversely to IO (which stands for Input/Output), 44 | -- user inputs shall be facilitated with a registry of 'MVar's, 45 | -- those get filled with 'IoC' from UI widgets. 46 | newtype UIO a = UIO { unUIO :: ReaderT UserInterfaceOutput IO a } 47 | deriving (Functor, Applicative, Monad, 48 | MonadReader UserInterfaceOutput, 49 | MonadIO, MonadThrow, MonadFail) 50 | 51 | instance PrimMonad UIO where 52 | type PrimState UIO = PrimState IO 53 | primitive = UIO . ReaderT . const . primitive 54 | 55 | instance HasLogFunc UserInterfaceOutput where 56 | logFuncL = lens haduiBackendLogFunc (\x y -> x { haduiBackendLogFunc = y }) 57 | 58 | 59 | -- | Run a 'UIO' action within any 'MonadIO' given a 'uio' env. 60 | runUIO :: MonadIO m => UserInterfaceOutput -> UIO a -> m a 61 | runUIO uio (UIO (ReaderT f)) = liftIO (f uio) 62 | 63 | 64 | -- | Every statement being executed dynamically by Hadui, is unlifted 65 | -- with this function into IO monad under the hood. 66 | -- 67 | -- This very explicitly hints the expected monad type in the dynamic 68 | -- compilation of such statements. 69 | mustUIO :: UIO a -> IO () 70 | mustUIO m = do 71 | uio <- readIORef _globalUIO 72 | !_v <- runUIO uio m -- force it to be evaluated 73 | pure () 74 | 75 | 76 | _globalUIO :: IORef UserInterfaceOutput 77 | {-# NOINLINE _globalUIO #-} 78 | _globalUIO = unsafePerformIO $ newIORef undefined 79 | 80 | 81 | -- | env of the UIO monad 82 | data UserInterfaceOutput = UserInterfaceOutput { 83 | -- | root directory of the stack project of matter 84 | haduiProjectRoot :: !FilePath 85 | 86 | -- | configuration loaded from `hadui.yaml` at project root 87 | , haduiConfig :: !HaduiConfig 88 | 89 | -- | arbitrary state managed by convention of the project 90 | , haduiAppData :: !(MVar (Maybe Dynamic)) 91 | 92 | -- | Global Interpreter Lock similar to Python's, but serializes 93 | -- executions of ws packets only, a single ws packet can trigger 94 | -- fully fledged concurrency and parallelism in contrast to Python. 95 | -- 96 | -- If a UIO action starts concurrent compution threads, and such 97 | -- a thread shall comm back to its originating ws, it must save 98 | -- the contextual websocket in GIL atm it's started. 99 | , haduiGIL :: !(MVar WS.Connection) 100 | 101 | -- | the underlying log function to implement rio's HasLogFunc 102 | , haduiBackendLogFunc :: !LogFunc 103 | 104 | -- | GHC session used to execute statements by dynamic compilation 105 | , haduiGhcSession :: !GHC.Session 106 | } 107 | 108 | -- | Initialize global UIO context with the calling Ghc Monad 109 | initUIO :: GHC.Ghc UserInterfaceOutput 110 | initUIO = do 111 | ghcSession <- GHC.reifyGhc return 112 | uio <- liftIO $ do 113 | prj <- loadHaduiConfig 114 | appData <- newMVar Nothing 115 | gil <- newEmptyMVar 116 | let !cfg = haduiCfg prj 117 | lo <- haduiBackendLogOpts cfg 118 | -- may need to teardown 'lf' on process exit, once the log target 119 | -- needs that, not needed as far as we only log to stderr. 120 | (lf, _ :: IO ()) <- newLogFunc lo 121 | return UserInterfaceOutput { haduiProjectRoot = projectRoot prj 122 | , haduiConfig = cfg 123 | , haduiAppData = appData 124 | , haduiGIL = gil 125 | , haduiBackendLogFunc = lf 126 | , haduiGhcSession = ghcSession 127 | } 128 | 129 | -- make module 'UIO' in scope implicitly 130 | GHC.getContext 131 | >>= GHC.setContext 132 | . ((GHC.IIDecl $ GHC.simpleImportDecl $ GHC.mkModuleName "UIO") :) 133 | -- to allow string and number literals without explicit type anno 134 | _ <- GHC.runDecls "default (Text,Int,Double)" 135 | 136 | -- XXX this does not work, have to use -fbreak-on-error on launching cmdl 137 | -- 138 | -- break on error/exception to print error location for debuggability 139 | -- dynFlags <- GHC.getSessionDynFlags 140 | -- let dynFlags' = dynFlags & GHC.setGeneralFlag' GHC.Opt_BreakOnError 141 | -- -- stop only on uncaught exceptions with mere above, 142 | -- -- following enables stop on any exception: 143 | -- -- . GHC.setGeneralFlag' GHC.Opt_BreakOnException 144 | -- _ <- GHC.setSessionDynFlags dynFlags' 145 | 146 | liftIO $ writeIORef _globalUIO uio 147 | return uio 148 | 149 | 150 | -- | Execute a UIO action with the specified ws for current context. 151 | -- 152 | -- Note this is designed to be called from forked threads by wsc actions. 153 | -- The wsc argument to use here is normally captured from 'haduiGIL' atm 154 | -- the calling thread is started. 155 | -- 156 | -- NEVER call this from threads directly triggered by UI, or it's deadlock. 157 | withHaduiFront :: WS.Connection -> UIO a -> UIO a 158 | withHaduiFront wsc action = do 159 | uio <- ask 160 | let gil = haduiGIL uio 161 | bracket_ (liftIO $ putMVar gil wsc) (liftIO $ takeMVar gil) action 162 | 163 | -------------------------------------------------------------------------------- /hadui/src/HaduiPub.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE NoImplicitPrelude #-} 2 | {-# LANGUAGE OverloadedStrings #-} 3 | {-# LANGUAGE ScopedTypeVariables #-} 4 | {-# LANGUAGE PartialTypeSignatures #-} 5 | {-# LANGUAGE BlockArguments #-} 6 | {-# LANGUAGE RankNTypes #-} 7 | {-# LANGUAGE FlexibleContexts #-} 8 | {-# LANGUAGE ExistentialQuantification #-} 9 | {-# LANGUAGE MultiParamTypeClasses #-} 10 | {-# LANGUAGE FlexibleInstances #-} 11 | {-# LANGUAGE TypeFamilies #-} 12 | {-# LANGUAGE UndecidableInstances #-} 13 | {-# LANGUAGE BangPatterns #-} 14 | 15 | module HaduiPub 16 | ( frontendPlugin 17 | ) 18 | where 19 | 20 | import RIO 21 | 22 | import GHC 23 | import Panic 24 | import GhcPlugins 25 | 26 | import HaduiRT 27 | 28 | 29 | frontendPlugin :: FrontendPlugin 30 | frontendPlugin = defaultFrontendPlugin { frontend = gfeMain } where 31 | -- GHC frontend plugin entry point 32 | gfeMain flags args = do 33 | unless (null args) $ throwGhcException $ CmdLineError 34 | "HaduiPub expects NO src" 35 | unless (null flags) $ throwGhcException $ CmdLineError 36 | "HaduiPub expects NO arg" 37 | 38 | haduiPubServer 39 | 40 | -------------------------------------------------------------------------------- /hadui/src/HaduiUtil.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE NoImplicitPrelude #-} 2 | {-# LANGUAGE OverloadedStrings #-} 3 | {-# LANGUAGE ExtendedDefaultRules #-} 4 | {-# LANGUAGE ScopedTypeVariables #-} 5 | {-# LANGUAGE BangPatterns #-} 6 | {-# LANGUAGE LambdaCase #-} 7 | {-# LANGUAGE QuasiQuotes #-} 8 | 9 | module HaduiUtil 10 | ( wsSendJson 11 | , wsSendData 12 | ) 13 | where 14 | 15 | import UIO 16 | 17 | import qualified RIO.ByteString.Lazy as BL 18 | import qualified RIO.Vector.Storable as VS 19 | import qualified RIO.Vector.Storable.Unsafe as VS' 20 | 21 | import qualified Data.ByteString.Unsafe as B' 22 | 23 | import qualified Network.WebSockets as WS 24 | import qualified Data.Aeson as A 25 | 26 | import Foreign 27 | 28 | 29 | wsSendJson :: (MonadIO m, A.ToJSON a) => WS.Connection -> a -> m () 30 | wsSendJson wsc jsonCmd = 31 | liftIO 32 | $ WS.sendDataMessage wsc 33 | $ flip WS.Text Nothing 34 | -- 'A.encode' may crash the process if lazily called here 35 | $! (A.encode jsonCmd) 36 | 37 | 38 | wsSendData 39 | :: forall m a 40 | . (MonadIO m, Storable a) 41 | => WS.Connection 42 | -> VS.Vector a 43 | -> m () 44 | wsSendData wsc arry = liftIO $ withForeignPtr fptr $ \ptr -> do 45 | -- we use unsafe coercion to ByteString here for zero-copy performance, 46 | -- it is safe as long as the caller is not modifying it concurrently, 47 | -- which obviously is not expected here. 48 | bs <- B'.unsafePackCStringLen (castPtr ptr, len * itemSize) 49 | WS.sendDataMessage wsc $ WS.Binary $ BL.fromStrict bs 50 | where 51 | !itemSize = sizeOf (undefined :: a) 52 | -- it's safe to use 'unsafeToForeignPtr0' as we never write to it here 53 | !(fptr, len) = VS'.unsafeToForeignPtr0 arry 54 | 55 | -------------------------------------------------------------------------------- /hadui/src/UIO.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE NoImplicitPrelude #-} 2 | 3 | module UIO 4 | ( module RIO -- re-export RIO, 5 | -- so UIO could be used as replacement prelude, too 6 | 7 | -- monad stuff 8 | , UIO(..) 9 | , UserInterfaceOutput(..) 10 | , runUIO 11 | 12 | -- comm functions 13 | , print 14 | , MsgToUI(..) 15 | , uiLog 16 | , uiClearLog 17 | , uiComm 18 | 19 | -- advanced harness 20 | , withHaduiFront 21 | , haduiExecStmt 22 | , haduiExecGhc 23 | , mustUIO 24 | ) 25 | where 26 | 27 | import RIO 28 | 29 | import HaduiMonad 30 | import HaduiRT 31 | 32 | 33 | -- | 'print' is just shorthand for 'uiLog . TextMsg . textDisplay' 34 | print :: Display a => a -> UIO () 35 | print = uiLog . TextMsg . textDisplay 36 | 37 | -------------------------------------------------------------------------------- /hadui/web/dev.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Hadui 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 | 38 | 39 |

40 | Hadui 41 | 42 | Web front UI for interactive Haskell projects 43 | docs 49 |

50 | 51 |
52 |
53 |
54 | 55 |
56 | 59 | 62 | 63 |
64 | 65 | 68 | 71 |
72 | 73 | -------------------------------------------------------------------------------- /hadui/web/dev.js: -------------------------------------------------------------------------------- 1 | /** 2 | * dev.js 3 | */ 4 | 5 | import { uiLog, clearLog } from "/log.js"; 6 | 7 | import { withHadui } from "/hadui.js"; 8 | 9 | import { HaduiDefaultStmt } from "./hadui-custom.js"; 10 | 11 | let mainCodeDiv = document.getElementById("main_code"); 12 | export const mainEditor = mainCodeDiv 13 | ? CodeMirror(mainCodeDiv, { 14 | value: HaduiDefaultStmt, 15 | lineNumbers: true, 16 | mode: "haskell", 17 | keyMap: "sublime", 18 | autoCloseBrackets: true, 19 | matchBrackets: true, 20 | showCursorWhenSelecting: true, 21 | theme: "monokai", 22 | tabSize: 2, 23 | viewportMargin: Infinity 24 | }) 25 | : null; 26 | 27 | $("button[name=crunch]").on("click", () => 28 | withHadui(ws => { 29 | let mainCode = mainEditor.getValue(); 30 | uiLog("Executing stmt:", "msg", mainCode); 31 | ws.send(mainEditor.getValue()); 32 | }) 33 | ); 34 | $("button[name=clear-log]").on("click", () => { 35 | clearLog(); 36 | }); 37 | -------------------------------------------------------------------------------- /hadui/web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/complyue/hadui/de221a453f32e02c50de52daf936b694267282c2/hadui/web/favicon.png -------------------------------------------------------------------------------- /hadui/web/front.html: -------------------------------------------------------------------------------- 1 | dev.html -------------------------------------------------------------------------------- /hadui/web/hadui-custom.css: -------------------------------------------------------------------------------- 1 | /** 2 | * hadui-custom.css 3 | */ 4 | -------------------------------------------------------------------------------- /hadui/web/hadui-custom.js: -------------------------------------------------------------------------------- 1 | /** 2 | * hadui-custom.js 3 | */ 4 | 5 | import WSC from "/wsc.js"; 6 | 7 | export const HaduiDefaultStmt = 8 | // the statement shown initially 9 | ` 10 | {- put and execute interactive Haskell statement here. 11 | you have the same artifacts in scope as \`stack ghci\`, 12 | with the \`UIO\` module implicitly imported in addition, 13 | so you get \`print\`, \`uiLog\` etc. -} 14 | print "Hello, web front!" 15 | `.trim(); 16 | 17 | export class HaduiWSC extends WSC { 18 | // implement ws methods here 19 | } 20 | -------------------------------------------------------------------------------- /hadui/web/hadui.css: -------------------------------------------------------------------------------- 1 | /** 2 | * hadui.css 3 | */ 4 | 5 | body { 6 | margin: 1px; 7 | padding: 1px 1px 1px 9pt; 8 | background: #383831; 9 | color: #f8f8f2; 10 | } 11 | 12 | .LogArea { 13 | display: block; 14 | flex: unset; /* will prevent resize if set */ 15 | overflow: scroll; 16 | resize: vertical; 17 | margin: 1px 1px; 18 | padding: 2px 5px 5px 2px; /* ensure resize handle visible */ 19 | border: 1px solid silver; 20 | background-color: #30312a; 21 | width: 96%; 22 | height: 150pt; 23 | min-height: 12pt; 24 | } 25 | 26 | .LogBox { 27 | display: flex; 28 | flex-flow: column nowrap; 29 | flex: unset; 30 | box-sizing: border-box; 31 | width: 100%; 32 | height: 100%; 33 | 34 | padding: 3px 1px; 35 | margin: 0; 36 | border: none; 37 | 38 | font-family: monospace; 39 | font-size: 9pt; 40 | } 41 | 42 | .LogBox .ts, 43 | .LogBox .msg, 44 | .LogBox .err-msg { 45 | font-family: monospace; 46 | margin: 1px 1px; 47 | padding: 0; 48 | line-height: 1; 49 | } 50 | 51 | .LogBox pre { 52 | margin-left: 12pt; 53 | } 54 | 55 | .LogBox .ts { 56 | margin-right: 6pt; 57 | color: #43a5e2; 58 | } 59 | 60 | .LogBox .msg { 61 | color: #cfa900; 62 | } 63 | 64 | .LogBox .err-msg { 65 | color: #bb5500; 66 | } 67 | 68 | .CodeMirror { 69 | border-top: 1px solid #eee; 70 | border-bottom: 1px solid #eee; 71 | line-height: 1.3; 72 | width: 98%; 73 | height: auto; 74 | } 75 | 76 | .CodeMirror-linenumbers { 77 | padding: 0 8px; 78 | } 79 | -------------------------------------------------------------------------------- /hadui/web/hadui.js: -------------------------------------------------------------------------------- 1 | /** 2 | * hadui.js 3 | */ 4 | 5 | import { uiLog } from "/log.js"; 6 | 7 | import { HaduiWSC } from "./hadui-custom.js"; 8 | 9 | export const haduiWSC = new HaduiWSC(); 10 | 11 | export async function withHadui(haduiAct) { 12 | let ws = await haduiWSC.dial(); 13 | haduiAct(ws); 14 | } 15 | 16 | $(async function() { 17 | try { 18 | uiLog("Dialing Hadui backend ..."); 19 | await haduiWSC.dial(); 20 | } catch (err) { 21 | let details = err ? err.stack : err; 22 | uiLog("Failed connecting to Hadui backend via ws.", "err-msg", details); 23 | } 24 | }); 25 | 26 | export default haduiWSC; 27 | -------------------------------------------------------------------------------- /hadui/web/log.js: -------------------------------------------------------------------------------- 1 | /** 2 | * log.js 3 | */ 4 | 5 | import NaiveDate from "/ts.js "; 6 | 7 | let logBox = $(".LogBox"), 8 | logArea = logBox.closest(".LogArea"); 9 | let lastAnimTime = 0, 10 | logAnimTask = null; 11 | 12 | export function hasLogBox() { 13 | return logBox.length > 0; 14 | } 15 | 16 | export function uiLog(msg, type = "msg", details = undefined) { 17 | if (!hasLogBox()) { 18 | console.log("Hadui:", type, msg, details); 19 | return; 20 | } 21 | 22 | let logRecord = $("
", { class: type }); 23 | let dt = new Date(); 24 | logRecord.append( 25 | $("", { 26 | class: "ts", 27 | text: 28 | "[" + 29 | new NaiveDate(dt.getTime() - 60000 * dt.getTimezoneOffset()).isoFull() + 30 | "]" 31 | }) 32 | ); 33 | 34 | msg = "" + msg; 35 | if (msg.includes("\n")) { 36 | logRecord.append($("
", { html: msg }));
37 |   } else {
38 |     logRecord.append($("", { text: msg }));
39 |   }
40 |   if (details) {
41 |     logRecord.append($("
", { html: "" + details }));
42 |   }
43 |   logBox.append(logRecord);
44 | 
45 |   // scroll new log with throttled animation, never trigger animation more frequent than 1Hz
46 |   function animNewLog() {
47 |     logArea.stop().animate({ scrollTop: logArea[0].scrollHeight }, 300);
48 |     lastAnimTime = dt.getTime();
49 |     logAnimTask = null;
50 |   }
51 | 
52 |   if (null !== logAnimTask) {
53 |     // animation scheduled
54 |     return;
55 |   }
56 |   let remainDelay = 1000 - (dt.getTime() - lastAnimTime);
57 |   if (remainDelay <= 0) {
58 |     logAnimTask = null;
59 |     animNewLog();
60 |   } else {
61 |     logAnimTask = setTimeout(animNewLog, remainDelay);
62 |   }
63 | }
64 | 
65 | export function clearLog() {
66 |   logBox.empty();
67 | }
68 | 
69 | export default uiLog;
70 | 


--------------------------------------------------------------------------------
/hadui/web/ts.js:
--------------------------------------------------------------------------------
  1 | /**
  2 |  * ts.js
  3 |  *
  4 |  * implementation of Naive dates with ISO8601 format
  5 |  */
  6 | export class NaiveDate {
  7 |   static get iNaT() {
  8 |     return -9223372036855;
  9 |   }
 10 | 
 11 |   static get NaT() {
 12 |     return new this(this.iNaT);
 13 |   }
 14 | 
 15 |   static get iNcT() {
 16 |     return 9223372036854;
 17 |   }
 18 | 
 19 |   static get NcT() {
 20 |     return new this(this.iNcT);
 21 |   }
 22 | 
 23 |   static parse(s) {
 24 |     if (!s) {
 25 |       return null;
 26 |     }
 27 |     s = String(s);
 28 | 
 29 |     if ("NaT" === s) {
 30 |       return this.NaT;
 31 |     }
 32 |     if ("NcT" === s) {
 33 |       return this.NcT;
 34 |     }
 35 | 
 36 |     return new NaiveDate(
 37 |       Date.UTC(
 38 |         parseInt(s.substr(0, 4)), // year
 39 |         s.length > 5 ? parseInt(s.substr(5, 2)) - 1 : 0, // month
 40 |         s.length > 8 ? parseInt(s.substr(8, 2)) : 1, // day
 41 |         s.length > 11 ? parseInt(s.substr(11, 2)) : 0, // hour
 42 |         s.length > 14 ? parseInt(s.substr(14, 2)) : 0, // min
 43 |         s.length > 17 ? parseInt(s.substr(17, 2)) : 0, // second
 44 |         s.length > 20 ? parseInt(s.substr(20, 3)) : 0 // millisecond
 45 |       )
 46 |     );
 47 |   }
 48 | 
 49 |   static str(ts) {
 50 |     return new NaiveDate(ts).str();
 51 |   }
 52 | 
 53 |   constructor(ts_or_date) {
 54 |     if (Object.is(ts_or_date, undefined)) {
 55 |       // shift current local time as if we are at UTC zone
 56 |       this.ts = Date.now() - new Date().getTimezoneOffset() * 60000;
 57 |     } else if (ts_or_date instanceof Date) {
 58 |       // shift specified local time as if we are at UTC zone
 59 |       this.ts = ts_or_date.getTime() - new Date().getTimezoneOffset() * 60000;
 60 |     } else if (Number.isSafeInteger(ts_or_date)) {
 61 |       // treat integer as milliseconds since epoch
 62 |       this.ts = ts_or_date;
 63 |     } else if ("NaT" === ts_or_date) {
 64 |       this.ts = this.constructor.iNaT;
 65 |     } else if ("NcT" === ts_or_date) {
 66 |       this.ts = this.constructor.iNcT;
 67 |     } else {
 68 |       throw "Invalid timestamp: " + ts_or_date;
 69 |     }
 70 |   }
 71 | 
 72 |   [Symbol.toPrimitive](hint) {
 73 |     if ("number" === hint) {
 74 |       return this.ts;
 75 |     }
 76 |     return this.str();
 77 |   }
 78 | 
 79 |   valueOf() {
 80 |     return this.ts;
 81 |   }
 82 | 
 83 |   toString() {
 84 |     return `NaiveDate("${this.str()}")`;
 85 |   }
 86 | 
 87 |   str(invalid_str) {
 88 |     if (this.ts === this.constructor.iNaT) {
 89 |       return "string" === typeof invalid_str ? invalid_str : "NaT";
 90 |     }
 91 |     if (this.ts === this.constructor.iNcT) {
 92 |       return "string" === typeof invalid_str ? invalid_str : "NcT";
 93 |     }
 94 | 
 95 |     const d = new Date(this.ts),
 96 |       d2 = this.constructor.d2,
 97 |       d3 = this.constructor.d3;
 98 |     if (d.getUTCMilliseconds() === 0) {
 99 |       if (d.getUTCSeconds() === 0) {
100 |         if (d.getUTCMinutes() === 0) {
101 |           if (d.getUTCHours() === 0) {
102 |             return this.isoDate();
103 |           }
104 |           return (
105 |             d.getUTCFullYear() +
106 |             "-" +
107 |             d2(d.getUTCMonth() + 1) +
108 |             "-" +
109 |             d2(d.getUTCDate()) +
110 |             "T" +
111 |             //
112 |             d2(d.getUTCHours())
113 |             //
114 |           );
115 |         }
116 |         return (
117 |           d.getUTCFullYear() +
118 |           "-" +
119 |           d2(d.getUTCMonth() + 1) +
120 |           "-" +
121 |           d2(d.getUTCDate()) +
122 |           "T" +
123 |           //
124 |           d2(d.getUTCHours()) +
125 |           ":" +
126 |           d2(d.getUTCMinutes())
127 |           //
128 |         );
129 |       }
130 |       return this.isoDateTime(invalid_str);
131 |     }
132 |     return this.isoFull(invalid_str);
133 |   }
134 | 
135 |   isoDate(invalid_str) {
136 |     if (this.ts === this.constructor.iNaT) {
137 |       return "string" === typeof invalid_str ? invalid_str : "NaT";
138 |     }
139 |     if (this.ts === this.constructor.iNcT) {
140 |       return "string" === typeof invalid_str ? invalid_str : "NcT";
141 |     }
142 | 
143 |     const d = new Date(this.ts),
144 |       d2 = this.constructor.d2,
145 |       d3 = this.constructor.d3;
146 |     return (
147 |       d.getUTCFullYear() +
148 |       "-" +
149 |       d2(d.getUTCMonth() + 1) +
150 |       "-" +
151 |       d2(d.getUTCDate())
152 |       //
153 |     );
154 |   }
155 | 
156 |   isoDateTime(invalid_str) {
157 |     if (this.ts === this.constructor.iNaT) {
158 |       return "string" === typeof invalid_str ? invalid_str : "NaT";
159 |     }
160 |     if (this.ts === this.constructor.iNcT) {
161 |       return "string" === typeof invalid_str ? invalid_str : "NcT";
162 |     }
163 | 
164 |     const d = new Date(this.ts),
165 |       d2 = this.constructor.d2,
166 |       d3 = this.constructor.d3;
167 |     return (
168 |       d.getUTCFullYear() +
169 |       "-" +
170 |       d2(d.getUTCMonth() + 1) +
171 |       "-" +
172 |       d2(d.getUTCDate()) +
173 |       "T" +
174 |       //
175 |       d2(d.getUTCHours()) +
176 |       ":" +
177 |       d2(d.getUTCMinutes()) +
178 |       ":" +
179 |       d2(d.getUTCSeconds())
180 |       //
181 |     );
182 |   }
183 | 
184 |   isoFull(invalid_str) {
185 |     if (this.ts === this.constructor.iNaT) {
186 |       return "string" === typeof invalid_str ? invalid_str : "NaT";
187 |     }
188 |     if (this.ts === this.constructor.iNcT) {
189 |       return "string" === typeof invalid_str ? invalid_str : "NcT";
190 |     }
191 | 
192 |     const d = new Date(this.ts),
193 |       d2 = this.constructor.d2,
194 |       d3 = this.constructor.d3;
195 |     return (
196 |       d.getUTCFullYear() +
197 |       "-" +
198 |       d2(d.getUTCMonth() + 1) +
199 |       "-" +
200 |       d2(d.getUTCDate()) +
201 |       "T" +
202 |       //
203 |       d2(d.getUTCHours()) +
204 |       ":" +
205 |       d2(d.getUTCMinutes()) +
206 |       ":" +
207 |       d2(d.getUTCSeconds()) +
208 |       "." +
209 |       //
210 |       d3(d.getUTCMilliseconds())
211 |       //
212 |     );
213 |   }
214 | 
215 |   idMonth(invalid_str) {
216 |     if (this.ts === this.constructor.iNaT) {
217 |       return "string" === typeof invalid_str ? invalid_str : "NaT";
218 |     }
219 |     if (this.ts === this.constructor.iNcT) {
220 |       return "string" === typeof invalid_str ? invalid_str : "NcT";
221 |     }
222 | 
223 |     const d = new Date(this.ts),
224 |       d2 = this.constructor.d2,
225 |       d3 = this.constructor.d3;
226 |     return (
227 |       d.getUTCFullYear() + d2(d.getUTCMonth() + 1)
228 |       //
229 |     );
230 |   }
231 | 
232 |   idDay(invalid_str) {
233 |     if (this.ts === this.constructor.iNaT) {
234 |       return "string" === typeof invalid_str ? invalid_str : "NaT";
235 |     }
236 |     if (this.ts === this.constructor.iNcT) {
237 |       return "string" === typeof invalid_str ? invalid_str : "NcT";
238 |     }
239 | 
240 |     const d = new Date(this.ts),
241 |       d2 = this.constructor.d2,
242 |       d3 = this.constructor.d3;
243 |     return (
244 |       d.getUTCFullYear() + d2(d.getUTCMonth() + 1) + d2(d.getUTCDate())
245 |       //
246 |     );
247 |   }
248 | 
249 |   idHMS(invalid_str) {
250 |     if (this.ts === this.constructor.iNaT) {
251 |       return "string" === typeof invalid_str ? invalid_str : "NaT";
252 |     }
253 |     if (this.ts === this.constructor.iNcT) {
254 |       return "string" === typeof invalid_str ? invalid_str : "NcT";
255 |     }
256 | 
257 |     const d = new Date(this.ts),
258 |       d2 = this.constructor.d2,
259 |       d3 = this.constructor.d3;
260 |     return (
261 |       d2(d.getUTCHours()) + d2(d.getUTCMinutes()) + d2(d.getUTCSeconds())
262 |       //
263 |     );
264 |   }
265 | 
266 |   idHMSS(invalid_str) {
267 |     if (this.ts === this.constructor.iNaT) {
268 |       return "string" === typeof invalid_str ? invalid_str : "NaT";
269 |     }
270 |     if (this.ts === this.constructor.iNcT) {
271 |       return "string" === typeof invalid_str ? invalid_str : "NcT";
272 |     }
273 | 
274 |     const d = new Date(this.ts),
275 |       d2 = this.constructor.d2,
276 |       d3 = this.constructor.d3;
277 |     return (
278 |       d2(d.getUTCHours()) +
279 |       d2(d.getUTCMinutes()) +
280 |       d2(d.getUTCSeconds()) +
281 |       d3(d.getUTCMilliseconds())
282 |       //
283 |     );
284 |   }
285 | 
286 |   static d2(i) {
287 |     if (i < 10) return "0" + i;
288 |     else return "" + i;
289 |   }
290 | 
291 |   static d3(i) {
292 |     if (i < 10) return "00" + i;
293 |     else if (i < 100) return "0" + i;
294 |     else return "" + i;
295 |   }
296 | }
297 | 
298 | export default NaiveDate;
299 | 


--------------------------------------------------------------------------------
/hadui/web/vendor/cm/LICENSE:
--------------------------------------------------------------------------------
 1 | MIT License
 2 | 
 3 | Copyright (C) 2017 by Marijn Haverbeke  and others
 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
13 | all 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
21 | THE SOFTWARE.
22 | 


--------------------------------------------------------------------------------
/hadui/web/vendor/cm/README.md:
--------------------------------------------------------------------------------
1 | # CodeMirror
2 | 
3 | Please check out https://github.com/codemirror/CodeMirror
4 | 


--------------------------------------------------------------------------------
/hadui/web/vendor/cm/addon/comment/comment.js:
--------------------------------------------------------------------------------
  1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
  2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
  3 | 
  4 | (function(mod) {
  5 |   if (typeof exports == "object" && typeof module == "object") // CommonJS
  6 |     mod(require("../../lib/codemirror"));
  7 |   else if (typeof define == "function" && define.amd) // AMD
  8 |     define(["../../lib/codemirror"], mod);
  9 |   else // Plain browser env
 10 |     mod(CodeMirror);
 11 | })(function(CodeMirror) {
 12 |   "use strict";
 13 | 
 14 |   var noOptions = {};
 15 |   var nonWS = /[^\s\u00a0]/;
 16 |   var Pos = CodeMirror.Pos;
 17 | 
 18 |   function firstNonWS(str) {
 19 |     var found = str.search(nonWS);
 20 |     return found == -1 ? 0 : found;
 21 |   }
 22 | 
 23 |   CodeMirror.commands.toggleComment = function(cm) {
 24 |     cm.toggleComment();
 25 |   };
 26 | 
 27 |   CodeMirror.defineExtension("toggleComment", function(options) {
 28 |     if (!options) options = noOptions;
 29 |     var cm = this;
 30 |     var minLine = Infinity, ranges = this.listSelections(), mode = null;
 31 |     for (var i = ranges.length - 1; i >= 0; i--) {
 32 |       var from = ranges[i].from(), to = ranges[i].to();
 33 |       if (from.line >= minLine) continue;
 34 |       if (to.line >= minLine) to = Pos(minLine, 0);
 35 |       minLine = from.line;
 36 |       if (mode == null) {
 37 |         if (cm.uncomment(from, to, options)) mode = "un";
 38 |         else { cm.lineComment(from, to, options); mode = "line"; }
 39 |       } else if (mode == "un") {
 40 |         cm.uncomment(from, to, options);
 41 |       } else {
 42 |         cm.lineComment(from, to, options);
 43 |       }
 44 |     }
 45 |   });
 46 | 
 47 |   // Rough heuristic to try and detect lines that are part of multi-line string
 48 |   function probablyInsideString(cm, pos, line) {
 49 |     return /\bstring\b/.test(cm.getTokenTypeAt(Pos(pos.line, 0))) && !/^[\'\"\`]/.test(line)
 50 |   }
 51 | 
 52 |   function getMode(cm, pos) {
 53 |     var mode = cm.getMode()
 54 |     return mode.useInnerComments === false || !mode.innerMode ? mode : cm.getModeAt(pos)
 55 |   }
 56 | 
 57 |   CodeMirror.defineExtension("lineComment", function(from, to, options) {
 58 |     if (!options) options = noOptions;
 59 |     var self = this, mode = getMode(self, from);
 60 |     var firstLine = self.getLine(from.line);
 61 |     if (firstLine == null || probablyInsideString(self, from, firstLine)) return;
 62 | 
 63 |     var commentString = options.lineComment || mode.lineComment;
 64 |     if (!commentString) {
 65 |       if (options.blockCommentStart || mode.blockCommentStart) {
 66 |         options.fullLines = true;
 67 |         self.blockComment(from, to, options);
 68 |       }
 69 |       return;
 70 |     }
 71 | 
 72 |     var end = Math.min(to.ch != 0 || to.line == from.line ? to.line + 1 : to.line, self.lastLine() + 1);
 73 |     var pad = options.padding == null ? " " : options.padding;
 74 |     var blankLines = options.commentBlankLines || from.line == to.line;
 75 | 
 76 |     self.operation(function() {
 77 |       if (options.indent) {
 78 |         var baseString = null;
 79 |         for (var i = from.line; i < end; ++i) {
 80 |           var line = self.getLine(i);
 81 |           var whitespace = line.slice(0, firstNonWS(line));
 82 |           if (baseString == null || baseString.length > whitespace.length) {
 83 |             baseString = whitespace;
 84 |           }
 85 |         }
 86 |         for (var i = from.line; i < end; ++i) {
 87 |           var line = self.getLine(i), cut = baseString.length;
 88 |           if (!blankLines && !nonWS.test(line)) continue;
 89 |           if (line.slice(0, cut) != baseString) cut = firstNonWS(line);
 90 |           self.replaceRange(baseString + commentString + pad, Pos(i, 0), Pos(i, cut));
 91 |         }
 92 |       } else {
 93 |         for (var i = from.line; i < end; ++i) {
 94 |           if (blankLines || nonWS.test(self.getLine(i)))
 95 |             self.replaceRange(commentString + pad, Pos(i, 0));
 96 |         }
 97 |       }
 98 |     });
 99 |   });
100 | 
101 |   CodeMirror.defineExtension("blockComment", function(from, to, options) {
102 |     if (!options) options = noOptions;
103 |     var self = this, mode = getMode(self, from);
104 |     var startString = options.blockCommentStart || mode.blockCommentStart;
105 |     var endString = options.blockCommentEnd || mode.blockCommentEnd;
106 |     if (!startString || !endString) {
107 |       if ((options.lineComment || mode.lineComment) && options.fullLines != false)
108 |         self.lineComment(from, to, options);
109 |       return;
110 |     }
111 |     if (/\bcomment\b/.test(self.getTokenTypeAt(Pos(from.line, 0)))) return
112 | 
113 |     var end = Math.min(to.line, self.lastLine());
114 |     if (end != from.line && to.ch == 0 && nonWS.test(self.getLine(end))) --end;
115 | 
116 |     var pad = options.padding == null ? " " : options.padding;
117 |     if (from.line > end) return;
118 | 
119 |     self.operation(function() {
120 |       if (options.fullLines != false) {
121 |         var lastLineHasText = nonWS.test(self.getLine(end));
122 |         self.replaceRange(pad + endString, Pos(end));
123 |         self.replaceRange(startString + pad, Pos(from.line, 0));
124 |         var lead = options.blockCommentLead || mode.blockCommentLead;
125 |         if (lead != null) for (var i = from.line + 1; i <= end; ++i)
126 |           if (i != end || lastLineHasText)
127 |             self.replaceRange(lead + pad, Pos(i, 0));
128 |       } else {
129 |         self.replaceRange(endString, to);
130 |         self.replaceRange(startString, from);
131 |       }
132 |     });
133 |   });
134 | 
135 |   CodeMirror.defineExtension("uncomment", function(from, to, options) {
136 |     if (!options) options = noOptions;
137 |     var self = this, mode = getMode(self, from);
138 |     var end = Math.min(to.ch != 0 || to.line == from.line ? to.line : to.line - 1, self.lastLine()), start = Math.min(from.line, end);
139 | 
140 |     // Try finding line comments
141 |     var lineString = options.lineComment || mode.lineComment, lines = [];
142 |     var pad = options.padding == null ? " " : options.padding, didSomething;
143 |     lineComment: {
144 |       if (!lineString) break lineComment;
145 |       for (var i = start; i <= end; ++i) {
146 |         var line = self.getLine(i);
147 |         var found = line.indexOf(lineString);
148 |         if (found > -1 && !/comment/.test(self.getTokenTypeAt(Pos(i, found + 1)))) found = -1;
149 |         if (found == -1 && nonWS.test(line)) break lineComment;
150 |         if (found > -1 && nonWS.test(line.slice(0, found))) break lineComment;
151 |         lines.push(line);
152 |       }
153 |       self.operation(function() {
154 |         for (var i = start; i <= end; ++i) {
155 |           var line = lines[i - start];
156 |           var pos = line.indexOf(lineString), endPos = pos + lineString.length;
157 |           if (pos < 0) continue;
158 |           if (line.slice(endPos, endPos + pad.length) == pad) endPos += pad.length;
159 |           didSomething = true;
160 |           self.replaceRange("", Pos(i, pos), Pos(i, endPos));
161 |         }
162 |       });
163 |       if (didSomething) return true;
164 |     }
165 | 
166 |     // Try block comments
167 |     var startString = options.blockCommentStart || mode.blockCommentStart;
168 |     var endString = options.blockCommentEnd || mode.blockCommentEnd;
169 |     if (!startString || !endString) return false;
170 |     var lead = options.blockCommentLead || mode.blockCommentLead;
171 |     var startLine = self.getLine(start), open = startLine.indexOf(startString)
172 |     if (open == -1) return false
173 |     var endLine = end == start ? startLine : self.getLine(end)
174 |     var close = endLine.indexOf(endString, end == start ? open + startString.length : 0);
175 |     var insideStart = Pos(start, open + 1), insideEnd = Pos(end, close + 1)
176 |     if (close == -1 ||
177 |         !/comment/.test(self.getTokenTypeAt(insideStart)) ||
178 |         !/comment/.test(self.getTokenTypeAt(insideEnd)) ||
179 |         self.getRange(insideStart, insideEnd, "\n").indexOf(endString) > -1)
180 |       return false;
181 | 
182 |     // Avoid killing block comments completely outside the selection.
183 |     // Positions of the last startString before the start of the selection, and the first endString after it.
184 |     var lastStart = startLine.lastIndexOf(startString, from.ch);
185 |     var firstEnd = lastStart == -1 ? -1 : startLine.slice(0, from.ch).indexOf(endString, lastStart + startString.length);
186 |     if (lastStart != -1 && firstEnd != -1 && firstEnd + endString.length != from.ch) return false;
187 |     // Positions of the first endString after the end of the selection, and the last startString before it.
188 |     firstEnd = endLine.indexOf(endString, to.ch);
189 |     var almostLastStart = endLine.slice(to.ch).lastIndexOf(startString, firstEnd - to.ch);
190 |     lastStart = (firstEnd == -1 || almostLastStart == -1) ? -1 : to.ch + almostLastStart;
191 |     if (firstEnd != -1 && lastStart != -1 && lastStart != to.ch) return false;
192 | 
193 |     self.operation(function() {
194 |       self.replaceRange("", Pos(end, close - (pad && endLine.slice(close - pad.length, close) == pad ? pad.length : 0)),
195 |                         Pos(end, close + endString.length));
196 |       var openEnd = open + startString.length;
197 |       if (pad && startLine.slice(openEnd, openEnd + pad.length) == pad) openEnd += pad.length;
198 |       self.replaceRange("", Pos(start, open), Pos(start, openEnd));
199 |       if (lead) for (var i = start + 1; i <= end; ++i) {
200 |         var line = self.getLine(i), found = line.indexOf(lead);
201 |         if (found == -1 || nonWS.test(line.slice(0, found))) continue;
202 |         var foundEnd = found + lead.length;
203 |         if (pad && line.slice(foundEnd, foundEnd + pad.length) == pad) foundEnd += pad.length;
204 |         self.replaceRange("", Pos(i, found), Pos(i, foundEnd));
205 |       }
206 |     });
207 |     return true;
208 |   });
209 | });
210 | 


--------------------------------------------------------------------------------
/hadui/web/vendor/cm/addon/comment/continuecomment.js:
--------------------------------------------------------------------------------
  1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
  2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
  3 | 
  4 | (function(mod) {
  5 |   if (typeof exports == "object" && typeof module == "object") // CommonJS
  6 |     mod(require("../../lib/codemirror"));
  7 |   else if (typeof define == "function" && define.amd) // AMD
  8 |     define(["../../lib/codemirror"], mod);
  9 |   else // Plain browser env
 10 |     mod(CodeMirror);
 11 | })(function(CodeMirror) {
 12 |   var nonspace = /\S/g;
 13 |   var repeat = String.prototype.repeat || function (n) { return Array(n + 1).join(this); };
 14 |   function continueComment(cm) {
 15 |     if (cm.getOption("disableInput")) return CodeMirror.Pass;
 16 |     var ranges = cm.listSelections(), mode, inserts = [];
 17 |     for (var i = 0; i < ranges.length; i++) {
 18 |       var pos = ranges[i].head
 19 |       if (!/\bcomment\b/.test(cm.getTokenTypeAt(pos))) return CodeMirror.Pass;
 20 |       var modeHere = cm.getModeAt(pos)
 21 |       if (!mode) mode = modeHere;
 22 |       else if (mode != modeHere) return CodeMirror.Pass;
 23 | 
 24 |       var insert = null, line, found;
 25 |       var blockStart = mode.blockCommentStart, lineCmt = mode.lineComment;
 26 |       if (blockStart && mode.blockCommentContinue) {
 27 |         line = cm.getLine(pos.line);
 28 |         var end = line.lastIndexOf(mode.blockCommentEnd, pos.ch - mode.blockCommentEnd.length);
 29 |         // 1. if this block comment ended
 30 |         // 2. if this is actually inside a line comment
 31 |         if (end != -1 && end == pos.ch - mode.blockCommentEnd.length ||
 32 |             lineCmt && (found = line.lastIndexOf(lineCmt, pos.ch - 1)) > -1 &&
 33 |             /\bcomment\b/.test(cm.getTokenTypeAt({line: pos.line, ch: found + 1}))) {
 34 |           // ...then don't continue it
 35 |         } else if ((found = line.lastIndexOf(blockStart, pos.ch - blockStart.length)) > -1 &&
 36 |                    found > end) {
 37 |           // reuse the existing leading spaces/tabs/mixed
 38 |           // or build the correct indent using CM's tab/indent options
 39 |           if (nonspaceAfter(0, line) >= found) {
 40 |             insert = line.slice(0, found);
 41 |           } else {
 42 |             var tabSize = cm.options.tabSize, numTabs;
 43 |             found = CodeMirror.countColumn(line, found, tabSize);
 44 |             insert = !cm.options.indentWithTabs ? repeat.call(" ", found) :
 45 |               repeat.call("\t", (numTabs = Math.floor(found / tabSize))) +
 46 |               repeat.call(" ", found - tabSize * numTabs);
 47 |           }
 48 |         } else if ((found = line.indexOf(mode.blockCommentContinue)) > -1 &&
 49 |                    found <= pos.ch &&
 50 |                    found <= nonspaceAfter(0, line)) {
 51 |           insert = line.slice(0, found);
 52 |         }
 53 |         if (insert != null) insert += mode.blockCommentContinue
 54 |       }
 55 |       if (insert == null && lineCmt && continueLineCommentEnabled(cm)) {
 56 |         if (line == null) line = cm.getLine(pos.line);
 57 |         found = line.indexOf(lineCmt);
 58 |         // cursor at pos 0, line comment also at pos 0 => shift it down, don't continue
 59 |         if (!pos.ch && !found) insert = "";
 60 |         // continue only if the line starts with an optional space + line comment
 61 |         else if (found > -1 && nonspaceAfter(0, line) >= found) {
 62 |           // don't continue if there's only space(s) after cursor or the end of the line
 63 |           insert = nonspaceAfter(pos.ch, line) > -1;
 64 |           // but always continue if the next line starts with a line comment too
 65 |           if (!insert) {
 66 |             var next = cm.getLine(pos.line + 1) || '',
 67 |                 nextFound = next.indexOf(lineCmt);
 68 |             insert = nextFound > -1 && nonspaceAfter(0, next) >= nextFound || null;
 69 |           }
 70 |           if (insert) {
 71 |             insert = line.slice(0, found) + lineCmt +
 72 |                      line.slice(found + lineCmt.length).match(/^\s*/)[0];
 73 |           }
 74 |         }
 75 |       }
 76 |       if (insert == null) return CodeMirror.Pass;
 77 |       inserts[i] = "\n" + insert;
 78 |     }
 79 | 
 80 |     cm.operation(function() {
 81 |       for (var i = ranges.length - 1; i >= 0; i--)
 82 |         cm.replaceRange(inserts[i], ranges[i].from(), ranges[i].to(), "+insert");
 83 |     });
 84 |   }
 85 | 
 86 |   function nonspaceAfter(ch, str) {
 87 |     nonspace.lastIndex = ch;
 88 |     var m = nonspace.exec(str);
 89 |     return m ? m.index : -1;
 90 |   }
 91 | 
 92 |   function continueLineCommentEnabled(cm) {
 93 |     var opt = cm.getOption("continueComments");
 94 |     if (opt && typeof opt == "object")
 95 |       return opt.continueLineComment !== false;
 96 |     return true;
 97 |   }
 98 | 
 99 |   CodeMirror.defineOption("continueComments", null, function(cm, val, prev) {
100 |     if (prev && prev != CodeMirror.Init)
101 |       cm.removeKeyMap("continueComment");
102 |     if (val) {
103 |       var key = "Enter";
104 |       if (typeof val == "string")
105 |         key = val;
106 |       else if (typeof val == "object" && val.key)
107 |         key = val.key;
108 |       var map = {name: "continueComment"};
109 |       map[key] = continueComment;
110 |       cm.addKeyMap(map);
111 |     }
112 |   });
113 | });
114 | 


--------------------------------------------------------------------------------
/hadui/web/vendor/cm/addon/dialog/dialog.css:
--------------------------------------------------------------------------------
 1 | .CodeMirror-dialog {
 2 |   position: absolute;
 3 |   left: 0; right: 0;
 4 |   background: inherit;
 5 |   z-index: 15;
 6 |   padding: .1em .8em;
 7 |   overflow: hidden;
 8 |   color: inherit;
 9 | }
10 | 
11 | .CodeMirror-dialog-top {
12 |   border-bottom: 1px solid #eee;
13 |   top: 0;
14 | }
15 | 
16 | .CodeMirror-dialog-bottom {
17 |   border-top: 1px solid #eee;
18 |   bottom: 0;
19 | }
20 | 
21 | .CodeMirror-dialog input {
22 |   border: none;
23 |   outline: none;
24 |   background: transparent;
25 |   width: 20em;
26 |   color: inherit;
27 |   font-family: monospace;
28 | }
29 | 
30 | .CodeMirror-dialog button {
31 |   font-size: 70%;
32 | }
33 | 


--------------------------------------------------------------------------------
/hadui/web/vendor/cm/addon/dialog/dialog.js:
--------------------------------------------------------------------------------
  1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
  2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
  3 | 
  4 | // Open simple dialogs on top of an editor. Relies on dialog.css.
  5 | 
  6 | (function(mod) {
  7 |   if (typeof exports == "object" && typeof module == "object") // CommonJS
  8 |     mod(require("../../lib/codemirror"));
  9 |   else if (typeof define == "function" && define.amd) // AMD
 10 |     define(["../../lib/codemirror"], mod);
 11 |   else // Plain browser env
 12 |     mod(CodeMirror);
 13 | })(function(CodeMirror) {
 14 |   function dialogDiv(cm, template, bottom) {
 15 |     var wrap = cm.getWrapperElement();
 16 |     var dialog;
 17 |     dialog = wrap.appendChild(document.createElement("div"));
 18 |     if (bottom)
 19 |       dialog.className = "CodeMirror-dialog CodeMirror-dialog-bottom";
 20 |     else
 21 |       dialog.className = "CodeMirror-dialog CodeMirror-dialog-top";
 22 | 
 23 |     if (typeof template == "string") {
 24 |       dialog.innerHTML = template;
 25 |     } else { // Assuming it's a detached DOM element.
 26 |       dialog.appendChild(template);
 27 |     }
 28 |     CodeMirror.addClass(wrap, 'dialog-opened');
 29 |     return dialog;
 30 |   }
 31 | 
 32 |   function closeNotification(cm, newVal) {
 33 |     if (cm.state.currentNotificationClose)
 34 |       cm.state.currentNotificationClose();
 35 |     cm.state.currentNotificationClose = newVal;
 36 |   }
 37 | 
 38 |   CodeMirror.defineExtension("openDialog", function(template, callback, options) {
 39 |     if (!options) options = {};
 40 | 
 41 |     closeNotification(this, null);
 42 | 
 43 |     var dialog = dialogDiv(this, template, options.bottom);
 44 |     var closed = false, me = this;
 45 |     function close(newVal) {
 46 |       if (typeof newVal == 'string') {
 47 |         inp.value = newVal;
 48 |       } else {
 49 |         if (closed) return;
 50 |         closed = true;
 51 |         CodeMirror.rmClass(dialog.parentNode, 'dialog-opened');
 52 |         dialog.parentNode.removeChild(dialog);
 53 |         me.focus();
 54 | 
 55 |         if (options.onClose) options.onClose(dialog);
 56 |       }
 57 |     }
 58 | 
 59 |     var inp = dialog.getElementsByTagName("input")[0], button;
 60 |     if (inp) {
 61 |       inp.focus();
 62 | 
 63 |       if (options.value) {
 64 |         inp.value = options.value;
 65 |         if (options.selectValueOnOpen !== false) {
 66 |           inp.select();
 67 |         }
 68 |       }
 69 | 
 70 |       if (options.onInput)
 71 |         CodeMirror.on(inp, "input", function(e) { options.onInput(e, inp.value, close);});
 72 |       if (options.onKeyUp)
 73 |         CodeMirror.on(inp, "keyup", function(e) {options.onKeyUp(e, inp.value, close);});
 74 | 
 75 |       CodeMirror.on(inp, "keydown", function(e) {
 76 |         if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; }
 77 |         if (e.keyCode == 27 || (options.closeOnEnter !== false && e.keyCode == 13)) {
 78 |           inp.blur();
 79 |           CodeMirror.e_stop(e);
 80 |           close();
 81 |         }
 82 |         if (e.keyCode == 13) callback(inp.value, e);
 83 |       });
 84 | 
 85 |       if (options.closeOnBlur !== false) CodeMirror.on(inp, "blur", close);
 86 |     } else if (button = dialog.getElementsByTagName("button")[0]) {
 87 |       CodeMirror.on(button, "click", function() {
 88 |         close();
 89 |         me.focus();
 90 |       });
 91 | 
 92 |       if (options.closeOnBlur !== false) CodeMirror.on(button, "blur", close);
 93 | 
 94 |       button.focus();
 95 |     }
 96 |     return close;
 97 |   });
 98 | 
 99 |   CodeMirror.defineExtension("openConfirm", function(template, callbacks, options) {
100 |     closeNotification(this, null);
101 |     var dialog = dialogDiv(this, template, options && options.bottom);
102 |     var buttons = dialog.getElementsByTagName("button");
103 |     var closed = false, me = this, blurring = 1;
104 |     function close() {
105 |       if (closed) return;
106 |       closed = true;
107 |       CodeMirror.rmClass(dialog.parentNode, 'dialog-opened');
108 |       dialog.parentNode.removeChild(dialog);
109 |       me.focus();
110 |     }
111 |     buttons[0].focus();
112 |     for (var i = 0; i < buttons.length; ++i) {
113 |       var b = buttons[i];
114 |       (function(callback) {
115 |         CodeMirror.on(b, "click", function(e) {
116 |           CodeMirror.e_preventDefault(e);
117 |           close();
118 |           if (callback) callback(me);
119 |         });
120 |       })(callbacks[i]);
121 |       CodeMirror.on(b, "blur", function() {
122 |         --blurring;
123 |         setTimeout(function() { if (blurring <= 0) close(); }, 200);
124 |       });
125 |       CodeMirror.on(b, "focus", function() { ++blurring; });
126 |     }
127 |   });
128 | 
129 |   /*
130 |    * openNotification
131 |    * Opens a notification, that can be closed with an optional timer
132 |    * (default 5000ms timer) and always closes on click.
133 |    *
134 |    * If a notification is opened while another is opened, it will close the
135 |    * currently opened one and open the new one immediately.
136 |    */
137 |   CodeMirror.defineExtension("openNotification", function(template, options) {
138 |     closeNotification(this, close);
139 |     var dialog = dialogDiv(this, template, options && options.bottom);
140 |     var closed = false, doneTimer;
141 |     var duration = options && typeof options.duration !== "undefined" ? options.duration : 5000;
142 | 
143 |     function close() {
144 |       if (closed) return;
145 |       closed = true;
146 |       clearTimeout(doneTimer);
147 |       CodeMirror.rmClass(dialog.parentNode, 'dialog-opened');
148 |       dialog.parentNode.removeChild(dialog);
149 |     }
150 | 
151 |     CodeMirror.on(dialog, 'click', function(e) {
152 |       CodeMirror.e_preventDefault(e);
153 |       close();
154 |     });
155 | 
156 |     if (duration)
157 |       doneTimer = setTimeout(close, duration);
158 | 
159 |     return close;
160 |   });
161 | });
162 | 


--------------------------------------------------------------------------------
/hadui/web/vendor/cm/addon/edit/closebrackets.js:
--------------------------------------------------------------------------------
  1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
  2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
  3 | 
  4 | (function(mod) {
  5 |   if (typeof exports == "object" && typeof module == "object") // CommonJS
  6 |     mod(require("../../lib/codemirror"));
  7 |   else if (typeof define == "function" && define.amd) // AMD
  8 |     define(["../../lib/codemirror"], mod);
  9 |   else // Plain browser env
 10 |     mod(CodeMirror);
 11 | })(function(CodeMirror) {
 12 |   var defaults = {
 13 |     pairs: "()[]{}''\"\"",
 14 |     closeBefore: ")]}'\":;>",
 15 |     triples: "",
 16 |     explode: "[]{}"
 17 |   };
 18 | 
 19 |   var Pos = CodeMirror.Pos;
 20 | 
 21 |   CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) {
 22 |     if (old && old != CodeMirror.Init) {
 23 |       cm.removeKeyMap(keyMap);
 24 |       cm.state.closeBrackets = null;
 25 |     }
 26 |     if (val) {
 27 |       ensureBound(getOption(val, "pairs"))
 28 |       cm.state.closeBrackets = val;
 29 |       cm.addKeyMap(keyMap);
 30 |     }
 31 |   });
 32 | 
 33 |   function getOption(conf, name) {
 34 |     if (name == "pairs" && typeof conf == "string") return conf;
 35 |     if (typeof conf == "object" && conf[name] != null) return conf[name];
 36 |     return defaults[name];
 37 |   }
 38 | 
 39 |   var keyMap = {Backspace: handleBackspace, Enter: handleEnter};
 40 |   function ensureBound(chars) {
 41 |     for (var i = 0; i < chars.length; i++) {
 42 |       var ch = chars.charAt(i), key = "'" + ch + "'"
 43 |       if (!keyMap[key]) keyMap[key] = handler(ch)
 44 |     }
 45 |   }
 46 |   ensureBound(defaults.pairs + "`")
 47 | 
 48 |   function handler(ch) {
 49 |     return function(cm) { return handleChar(cm, ch); };
 50 |   }
 51 | 
 52 |   function getConfig(cm) {
 53 |     var deflt = cm.state.closeBrackets;
 54 |     if (!deflt || deflt.override) return deflt;
 55 |     var mode = cm.getModeAt(cm.getCursor());
 56 |     return mode.closeBrackets || deflt;
 57 |   }
 58 | 
 59 |   function handleBackspace(cm) {
 60 |     var conf = getConfig(cm);
 61 |     if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass;
 62 | 
 63 |     var pairs = getOption(conf, "pairs");
 64 |     var ranges = cm.listSelections();
 65 |     for (var i = 0; i < ranges.length; i++) {
 66 |       if (!ranges[i].empty()) return CodeMirror.Pass;
 67 |       var around = charsAround(cm, ranges[i].head);
 68 |       if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass;
 69 |     }
 70 |     for (var i = ranges.length - 1; i >= 0; i--) {
 71 |       var cur = ranges[i].head;
 72 |       cm.replaceRange("", Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1), "+delete");
 73 |     }
 74 |   }
 75 | 
 76 |   function handleEnter(cm) {
 77 |     var conf = getConfig(cm);
 78 |     var explode = conf && getOption(conf, "explode");
 79 |     if (!explode || cm.getOption("disableInput")) return CodeMirror.Pass;
 80 | 
 81 |     var ranges = cm.listSelections();
 82 |     for (var i = 0; i < ranges.length; i++) {
 83 |       if (!ranges[i].empty()) return CodeMirror.Pass;
 84 |       var around = charsAround(cm, ranges[i].head);
 85 |       if (!around || explode.indexOf(around) % 2 != 0) return CodeMirror.Pass;
 86 |     }
 87 |     cm.operation(function() {
 88 |       var linesep = cm.lineSeparator() || "\n";
 89 |       cm.replaceSelection(linesep + linesep, null);
 90 |       cm.execCommand("goCharLeft");
 91 |       ranges = cm.listSelections();
 92 |       for (var i = 0; i < ranges.length; i++) {
 93 |         var line = ranges[i].head.line;
 94 |         cm.indentLine(line, null, true);
 95 |         cm.indentLine(line + 1, null, true);
 96 |       }
 97 |     });
 98 |   }
 99 | 
100 |   function contractSelection(sel) {
101 |     var inverted = CodeMirror.cmpPos(sel.anchor, sel.head) > 0;
102 |     return {anchor: new Pos(sel.anchor.line, sel.anchor.ch + (inverted ? -1 : 1)),
103 |             head: new Pos(sel.head.line, sel.head.ch + (inverted ? 1 : -1))};
104 |   }
105 | 
106 |   function handleChar(cm, ch) {
107 |     var conf = getConfig(cm);
108 |     if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass;
109 | 
110 |     var pairs = getOption(conf, "pairs");
111 |     var pos = pairs.indexOf(ch);
112 |     if (pos == -1) return CodeMirror.Pass;
113 | 
114 |     var closeBefore = getOption(conf,"closeBefore");
115 | 
116 |     var triples = getOption(conf, "triples");
117 | 
118 |     var identical = pairs.charAt(pos + 1) == ch;
119 |     var ranges = cm.listSelections();
120 |     var opening = pos % 2 == 0;
121 | 
122 |     var type;
123 |     for (var i = 0; i < ranges.length; i++) {
124 |       var range = ranges[i], cur = range.head, curType;
125 |       var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1));
126 |       if (opening && !range.empty()) {
127 |         curType = "surround";
128 |       } else if ((identical || !opening) && next == ch) {
129 |         if (identical && stringStartsAfter(cm, cur))
130 |           curType = "both";
131 |         else if (triples.indexOf(ch) >= 0 && cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == ch + ch + ch)
132 |           curType = "skipThree";
133 |         else
134 |           curType = "skip";
135 |       } else if (identical && cur.ch > 1 && triples.indexOf(ch) >= 0 &&
136 |                  cm.getRange(Pos(cur.line, cur.ch - 2), cur) == ch + ch) {
137 |         if (cur.ch > 2 && /\bstring/.test(cm.getTokenTypeAt(Pos(cur.line, cur.ch - 2)))) return CodeMirror.Pass;
138 |         curType = "addFour";
139 |       } else if (identical) {
140 |         var prev = cur.ch == 0 ? " " : cm.getRange(Pos(cur.line, cur.ch - 1), cur)
141 |         if (!CodeMirror.isWordChar(next) && prev != ch && !CodeMirror.isWordChar(prev)) curType = "both";
142 |         else return CodeMirror.Pass;
143 |       } else if (opening && (next.length === 0 || /\s/.test(next) || closeBefore.indexOf(next) > -1)) {
144 |         curType = "both";
145 |       } else {
146 |         return CodeMirror.Pass;
147 |       }
148 |       if (!type) type = curType;
149 |       else if (type != curType) return CodeMirror.Pass;
150 |     }
151 | 
152 |     var left = pos % 2 ? pairs.charAt(pos - 1) : ch;
153 |     var right = pos % 2 ? ch : pairs.charAt(pos + 1);
154 |     cm.operation(function() {
155 |       if (type == "skip") {
156 |         cm.execCommand("goCharRight");
157 |       } else if (type == "skipThree") {
158 |         for (var i = 0; i < 3; i++)
159 |           cm.execCommand("goCharRight");
160 |       } else if (type == "surround") {
161 |         var sels = cm.getSelections();
162 |         for (var i = 0; i < sels.length; i++)
163 |           sels[i] = left + sels[i] + right;
164 |         cm.replaceSelections(sels, "around");
165 |         sels = cm.listSelections().slice();
166 |         for (var i = 0; i < sels.length; i++)
167 |           sels[i] = contractSelection(sels[i]);
168 |         cm.setSelections(sels);
169 |       } else if (type == "both") {
170 |         cm.replaceSelection(left + right, null);
171 |         cm.triggerElectric(left + right);
172 |         cm.execCommand("goCharLeft");
173 |       } else if (type == "addFour") {
174 |         cm.replaceSelection(left + left + left + left, "before");
175 |         cm.execCommand("goCharRight");
176 |       }
177 |     });
178 |   }
179 | 
180 |   function charsAround(cm, pos) {
181 |     var str = cm.getRange(Pos(pos.line, pos.ch - 1),
182 |                           Pos(pos.line, pos.ch + 1));
183 |     return str.length == 2 ? str : null;
184 |   }
185 | 
186 |   function stringStartsAfter(cm, pos) {
187 |     var token = cm.getTokenAt(Pos(pos.line, pos.ch + 1))
188 |     return /\bstring/.test(token.type) && token.start == pos.ch &&
189 |       (pos.ch == 0 || !/\bstring/.test(cm.getTokenTypeAt(pos)))
190 |   }
191 | });
192 | 


--------------------------------------------------------------------------------
/hadui/web/vendor/cm/addon/edit/closetag.js:
--------------------------------------------------------------------------------
  1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
  2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
  3 | 
  4 | /**
  5 |  * Tag-closer extension for CodeMirror.
  6 |  *
  7 |  * This extension adds an "autoCloseTags" option that can be set to
  8 |  * either true to get the default behavior, or an object to further
  9 |  * configure its behavior.
 10 |  *
 11 |  * These are supported options:
 12 |  *
 13 |  * `whenClosing` (default true)
 14 |  *   Whether to autoclose when the '/' of a closing tag is typed.
 15 |  * `whenOpening` (default true)
 16 |  *   Whether to autoclose the tag when the final '>' of an opening
 17 |  *   tag is typed.
 18 |  * `dontCloseTags` (default is empty tags for HTML, none for XML)
 19 |  *   An array of tag names that should not be autoclosed.
 20 |  * `indentTags` (default is block tags for HTML, none for XML)
 21 |  *   An array of tag names that should, when opened, cause a
 22 |  *   blank line to be added inside the tag, and the blank line and
 23 |  *   closing line to be indented.
 24 |  * `emptyTags` (default is none)
 25 |  *   An array of XML tag names that should be autoclosed with '/>'.
 26 |  *
 27 |  * See demos/closetag.html for a usage example.
 28 |  */
 29 | 
 30 | (function(mod) {
 31 |   if (typeof exports == "object" && typeof module == "object") // CommonJS
 32 |     mod(require("../../lib/codemirror"), require("../fold/xml-fold"));
 33 |   else if (typeof define == "function" && define.amd) // AMD
 34 |     define(["../../lib/codemirror", "../fold/xml-fold"], mod);
 35 |   else // Plain browser env
 36 |     mod(CodeMirror);
 37 | })(function(CodeMirror) {
 38 |   CodeMirror.defineOption("autoCloseTags", false, function(cm, val, old) {
 39 |     if (old != CodeMirror.Init && old)
 40 |       cm.removeKeyMap("autoCloseTags");
 41 |     if (!val) return;
 42 |     var map = {name: "autoCloseTags"};
 43 |     if (typeof val != "object" || val.whenClosing)
 44 |       map["'/'"] = function(cm) { return autoCloseSlash(cm); };
 45 |     if (typeof val != "object" || val.whenOpening)
 46 |       map["'>'"] = function(cm) { return autoCloseGT(cm); };
 47 |     cm.addKeyMap(map);
 48 |   });
 49 | 
 50 |   var htmlDontClose = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param",
 51 |                        "source", "track", "wbr"];
 52 |   var htmlIndent = ["applet", "blockquote", "body", "button", "div", "dl", "fieldset", "form", "frameset", "h1", "h2", "h3", "h4",
 53 |                     "h5", "h6", "head", "html", "iframe", "layer", "legend", "object", "ol", "p", "select", "table", "ul"];
 54 | 
 55 |   function autoCloseGT(cm) {
 56 |     if (cm.getOption("disableInput")) return CodeMirror.Pass;
 57 |     var ranges = cm.listSelections(), replacements = [];
 58 |     var opt = cm.getOption("autoCloseTags");
 59 |     for (var i = 0; i < ranges.length; i++) {
 60 |       if (!ranges[i].empty()) return CodeMirror.Pass;
 61 |       var pos = ranges[i].head, tok = cm.getTokenAt(pos);
 62 |       var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;
 63 |       var tagInfo = inner.mode.xmlCurrentTag && inner.mode.xmlCurrentTag(state)
 64 |       var tagName = tagInfo && tagInfo.name
 65 |       if (!tagName) return CodeMirror.Pass
 66 | 
 67 |       var html = inner.mode.configuration == "html";
 68 |       var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose);
 69 |       var indentTags = (typeof opt == "object" && opt.indentTags) || (html && htmlIndent);
 70 | 
 71 |       if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch);
 72 |       var lowerTagName = tagName.toLowerCase();
 73 |       // Don't process the '>' at the end of an end-tag or self-closing tag
 74 |       if (!tagName ||
 75 |           tok.type == "string" && (tok.end != pos.ch || !/[\"\']/.test(tok.string.charAt(tok.string.length - 1)) || tok.string.length == 1) ||
 76 |           tok.type == "tag" && tagInfo.close ||
 77 |           tok.string.indexOf("/") == (tok.string.length - 1) || // match something like 
 78 |           dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1 ||
 79 |           closingTagExists(cm, inner.mode.xmlCurrentContext && inner.mode.xmlCurrentContext(state) || [], tagName, pos, true))
 80 |         return CodeMirror.Pass;
 81 | 
 82 |       var emptyTags = typeof opt == "object" && opt.emptyTags;
 83 |       if (emptyTags && indexOf(emptyTags, tagName) > -1) {
 84 |         replacements[i] = { text: "/>", newPos: CodeMirror.Pos(pos.line, pos.ch + 2) };
 85 |         continue;
 86 |       }
 87 | 
 88 |       var indent = indentTags && indexOf(indentTags, lowerTagName) > -1;
 89 |       replacements[i] = {indent: indent,
 90 |                          text: ">" + (indent ? "\n\n" : "") + "",
 91 |                          newPos: indent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1)};
 92 |     }
 93 | 
 94 |     var dontIndentOnAutoClose = (typeof opt == "object" && opt.dontIndentOnAutoClose);
 95 |     for (var i = ranges.length - 1; i >= 0; i--) {
 96 |       var info = replacements[i];
 97 |       cm.replaceRange(info.text, ranges[i].head, ranges[i].anchor, "+insert");
 98 |       var sel = cm.listSelections().slice(0);
 99 |       sel[i] = {head: info.newPos, anchor: info.newPos};
100 |       cm.setSelections(sel);
101 |       if (!dontIndentOnAutoClose && info.indent) {
102 |         cm.indentLine(info.newPos.line, null, true);
103 |         cm.indentLine(info.newPos.line + 1, null, true);
104 |       }
105 |     }
106 |   }
107 | 
108 |   function autoCloseCurrent(cm, typingSlash) {
109 |     var ranges = cm.listSelections(), replacements = [];
110 |     var head = typingSlash ? "/" : "") replacement += ">";
136 |       replacements[i] = replacement;
137 |     }
138 |     cm.replaceSelections(replacements);
139 |     ranges = cm.listSelections();
140 |     if (!dontIndentOnAutoClose) {
141 |         for (var i = 0; i < ranges.length; i++)
142 |             if (i == ranges.length - 1 || ranges[i].head.line < ranges[i + 1].head.line)
143 |                 cm.indentLine(ranges[i].head.line);
144 |     }
145 |   }
146 | 
147 |   function autoCloseSlash(cm) {
148 |     if (cm.getOption("disableInput")) return CodeMirror.Pass;
149 |     return autoCloseCurrent(cm, true);
150 |   }
151 | 
152 |   CodeMirror.commands.closeTag = function(cm) { return autoCloseCurrent(cm); };
153 | 
154 |   function indexOf(collection, elt) {
155 |     if (collection.indexOf) return collection.indexOf(elt);
156 |     for (var i = 0, e = collection.length; i < e; ++i)
157 |       if (collection[i] == elt) return i;
158 |     return -1;
159 |   }
160 | 
161 |   // If xml-fold is loaded, we use its functionality to try and verify
162 |   // whether a given tag is actually unclosed.
163 |   function closingTagExists(cm, context, tagName, pos, newTag) {
164 |     if (!CodeMirror.scanForClosingTag) return false;
165 |     var end = Math.min(cm.lastLine() + 1, pos.line + 500);
166 |     var nextClose = CodeMirror.scanForClosingTag(cm, pos, null, end);
167 |     if (!nextClose || nextClose.tag != tagName) return false;
168 |     // If the immediate wrapping context contains onCx instances of
169 |     // the same tag, a closing tag only exists if there are at least
170 |     // that many closing tags of that type following.
171 |     var onCx = newTag ? 1 : 0
172 |     for (var i = context.length - 1; i >= 0; i--) {
173 |       if (context[i] == tagName) ++onCx
174 |       else break
175 |     }
176 |     pos = nextClose.to;
177 |     for (var i = 1; i < onCx; i++) {
178 |       var next = CodeMirror.scanForClosingTag(cm, pos, null, end);
179 |       if (!next || next.tag != tagName) return false;
180 |       pos = next.to;
181 |     }
182 |     return true;
183 |   }
184 | });
185 | 


--------------------------------------------------------------------------------
/hadui/web/vendor/cm/addon/edit/continuelist.js:
--------------------------------------------------------------------------------
  1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
  2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
  3 | 
  4 | (function(mod) {
  5 |   if (typeof exports == "object" && typeof module == "object") // CommonJS
  6 |     mod(require("../../lib/codemirror"));
  7 |   else if (typeof define == "function" && define.amd) // AMD
  8 |     define(["../../lib/codemirror"], mod);
  9 |   else // Plain browser env
 10 |     mod(CodeMirror);
 11 | })(function(CodeMirror) {
 12 |   "use strict";
 13 | 
 14 |   var listRE = /^(\s*)(>[> ]*|[*+-] \[[x ]\]\s|[*+-]\s|(\d+)([.)]))(\s*)/,
 15 |       emptyListRE = /^(\s*)(>[> ]*|[*+-] \[[x ]\]|[*+-]|(\d+)[.)])(\s*)$/,
 16 |       unorderedListRE = /[*+-]\s/;
 17 | 
 18 |   CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) {
 19 |     if (cm.getOption("disableInput")) return CodeMirror.Pass;
 20 |     var ranges = cm.listSelections(), replacements = [];
 21 |     for (var i = 0; i < ranges.length; i++) {
 22 |       var pos = ranges[i].head;
 23 | 
 24 |       // If we're not in Markdown mode, fall back to normal newlineAndIndent
 25 |       var eolState = cm.getStateAfter(pos.line);
 26 |       var inner = CodeMirror.innerMode(cm.getMode(), eolState);
 27 |       if (inner.mode.name !== "markdown") {
 28 |         cm.execCommand("newlineAndIndent");
 29 |         return;
 30 |       } else {
 31 |         eolState = inner.state;
 32 |       }
 33 | 
 34 |       var inList = eolState.list !== false;
 35 |       var inQuote = eolState.quote !== 0;
 36 | 
 37 |       var line = cm.getLine(pos.line), match = listRE.exec(line);
 38 |       var cursorBeforeBullet = /^\s*$/.test(line.slice(0, pos.ch));
 39 |       if (!ranges[i].empty() || (!inList && !inQuote) || !match || cursorBeforeBullet) {
 40 |         cm.execCommand("newlineAndIndent");
 41 |         return;
 42 |       }
 43 |       if (emptyListRE.test(line)) {
 44 |         if (!/>\s*$/.test(line)) cm.replaceRange("", {
 45 |           line: pos.line, ch: 0
 46 |         }, {
 47 |           line: pos.line, ch: pos.ch + 1
 48 |         });
 49 |         replacements[i] = "\n";
 50 |       } else {
 51 |         var indent = match[1], after = match[5];
 52 |         var numbered = !(unorderedListRE.test(match[2]) || match[2].indexOf(">") >= 0);
 53 |         var bullet = numbered ? (parseInt(match[3], 10) + 1) + match[4] : match[2].replace("x", " ");
 54 |         replacements[i] = "\n" + indent + bullet + after;
 55 | 
 56 |         if (numbered) incrementRemainingMarkdownListNumbers(cm, pos);
 57 |       }
 58 |     }
 59 | 
 60 |     cm.replaceSelections(replacements);
 61 |   };
 62 | 
 63 |   // Auto-updating Markdown list numbers when a new item is added to the
 64 |   // middle of a list
 65 |   function incrementRemainingMarkdownListNumbers(cm, pos) {
 66 |     var startLine = pos.line, lookAhead = 0, skipCount = 0;
 67 |     var startItem = listRE.exec(cm.getLine(startLine)), startIndent = startItem[1];
 68 | 
 69 |     do {
 70 |       lookAhead += 1;
 71 |       var nextLineNumber = startLine + lookAhead;
 72 |       var nextLine = cm.getLine(nextLineNumber), nextItem = listRE.exec(nextLine);
 73 | 
 74 |       if (nextItem) {
 75 |         var nextIndent = nextItem[1];
 76 |         var newNumber = (parseInt(startItem[3], 10) + lookAhead - skipCount);
 77 |         var nextNumber = (parseInt(nextItem[3], 10)), itemNumber = nextNumber;
 78 | 
 79 |         if (startIndent === nextIndent && !isNaN(nextNumber)) {
 80 |           if (newNumber === nextNumber) itemNumber = nextNumber + 1;
 81 |           if (newNumber > nextNumber) itemNumber = newNumber + 1;
 82 |           cm.replaceRange(
 83 |             nextLine.replace(listRE, nextIndent + itemNumber + nextItem[4] + nextItem[5]),
 84 |           {
 85 |             line: nextLineNumber, ch: 0
 86 |           }, {
 87 |             line: nextLineNumber, ch: nextLine.length
 88 |           });
 89 |         } else {
 90 |           if (startIndent.length > nextIndent.length) return;
 91 |           // This doesn't run if the next line immediatley indents, as it is
 92 |           // not clear of the users intention (new indented item or same level)
 93 |           if ((startIndent.length < nextIndent.length) && (lookAhead === 1)) return;
 94 |           skipCount += 1;
 95 |         }
 96 |       }
 97 |     } while (nextItem);
 98 |   }
 99 | });
100 | 


--------------------------------------------------------------------------------
/hadui/web/vendor/cm/addon/edit/matchbrackets.js:
--------------------------------------------------------------------------------
  1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
  2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
  3 | 
  4 | (function(mod) {
  5 |   if (typeof exports == "object" && typeof module == "object") // CommonJS
  6 |     mod(require("../../lib/codemirror"));
  7 |   else if (typeof define == "function" && define.amd) // AMD
  8 |     define(["../../lib/codemirror"], mod);
  9 |   else // Plain browser env
 10 |     mod(CodeMirror);
 11 | })(function(CodeMirror) {
 12 |   var ie_lt8 = /MSIE \d/.test(navigator.userAgent) &&
 13 |     (document.documentMode == null || document.documentMode < 8);
 14 | 
 15 |   var Pos = CodeMirror.Pos;
 16 | 
 17 |   var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<", "<": ">>", ">": "<<"};
 18 | 
 19 |   function bracketRegex(config) {
 20 |     return config && config.bracketRegex || /[(){}[\]]/
 21 |   }
 22 | 
 23 |   function findMatchingBracket(cm, where, config) {
 24 |     var line = cm.getLineHandle(where.line), pos = where.ch - 1;
 25 |     var afterCursor = config && config.afterCursor
 26 |     if (afterCursor == null)
 27 |       afterCursor = /(^| )cm-fat-cursor($| )/.test(cm.getWrapperElement().className)
 28 |     var re = bracketRegex(config)
 29 | 
 30 |     // A cursor is defined as between two characters, but in in vim command mode
 31 |     // (i.e. not insert mode), the cursor is visually represented as a
 32 |     // highlighted box on top of the 2nd character. Otherwise, we allow matches
 33 |     // from before or after the cursor.
 34 |     var match = (!afterCursor && pos >= 0 && re.test(line.text.charAt(pos)) && matching[line.text.charAt(pos)]) ||
 35 |         re.test(line.text.charAt(pos + 1)) && matching[line.text.charAt(++pos)];
 36 |     if (!match) return null;
 37 |     var dir = match.charAt(1) == ">" ? 1 : -1;
 38 |     if (config && config.strict && (dir > 0) != (pos == where.ch)) return null;
 39 |     var style = cm.getTokenTypeAt(Pos(where.line, pos + 1));
 40 | 
 41 |     var found = scanForBracket(cm, Pos(where.line, pos + (dir > 0 ? 1 : 0)), dir, style || null, config);
 42 |     if (found == null) return null;
 43 |     return {from: Pos(where.line, pos), to: found && found.pos,
 44 |             match: found && found.ch == match.charAt(0), forward: dir > 0};
 45 |   }
 46 | 
 47 |   // bracketRegex is used to specify which type of bracket to scan
 48 |   // should be a regexp, e.g. /[[\]]/
 49 |   //
 50 |   // Note: If "where" is on an open bracket, then this bracket is ignored.
 51 |   //
 52 |   // Returns false when no bracket was found, null when it reached
 53 |   // maxScanLines and gave up
 54 |   function scanForBracket(cm, where, dir, style, config) {
 55 |     var maxScanLen = (config && config.maxScanLineLength) || 10000;
 56 |     var maxScanLines = (config && config.maxScanLines) || 1000;
 57 | 
 58 |     var stack = [];
 59 |     var re = bracketRegex(config)
 60 |     var lineEnd = dir > 0 ? Math.min(where.line + maxScanLines, cm.lastLine() + 1)
 61 |                           : Math.max(cm.firstLine() - 1, where.line - maxScanLines);
 62 |     for (var lineNo = where.line; lineNo != lineEnd; lineNo += dir) {
 63 |       var line = cm.getLine(lineNo);
 64 |       if (!line) continue;
 65 |       var pos = dir > 0 ? 0 : line.length - 1, end = dir > 0 ? line.length : -1;
 66 |       if (line.length > maxScanLen) continue;
 67 |       if (lineNo == where.line) pos = where.ch - (dir < 0 ? 1 : 0);
 68 |       for (; pos != end; pos += dir) {
 69 |         var ch = line.charAt(pos);
 70 |         if (re.test(ch) && (style === undefined || cm.getTokenTypeAt(Pos(lineNo, pos + 1)) == style)) {
 71 |           var match = matching[ch];
 72 |           if (match && (match.charAt(1) == ">") == (dir > 0)) stack.push(ch);
 73 |           else if (!stack.length) return {pos: Pos(lineNo, pos), ch: ch};
 74 |           else stack.pop();
 75 |         }
 76 |       }
 77 |     }
 78 |     return lineNo - dir == (dir > 0 ? cm.lastLine() : cm.firstLine()) ? false : null;
 79 |   }
 80 | 
 81 |   function matchBrackets(cm, autoclear, config) {
 82 |     // Disable brace matching in long lines, since it'll cause hugely slow updates
 83 |     var maxHighlightLen = cm.state.matchBrackets.maxHighlightLineLength || 1000;
 84 |     var marks = [], ranges = cm.listSelections();
 85 |     for (var i = 0; i < ranges.length; i++) {
 86 |       var match = ranges[i].empty() && findMatchingBracket(cm, ranges[i].head, config);
 87 |       if (match && cm.getLine(match.from.line).length <= maxHighlightLen) {
 88 |         var style = match.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket";
 89 |         marks.push(cm.markText(match.from, Pos(match.from.line, match.from.ch + 1), {className: style}));
 90 |         if (match.to && cm.getLine(match.to.line).length <= maxHighlightLen)
 91 |           marks.push(cm.markText(match.to, Pos(match.to.line, match.to.ch + 1), {className: style}));
 92 |       }
 93 |     }
 94 | 
 95 |     if (marks.length) {
 96 |       // Kludge to work around the IE bug from issue #1193, where text
 97 |       // input stops going to the textare whever this fires.
 98 |       if (ie_lt8 && cm.state.focused) cm.focus();
 99 | 
100 |       var clear = function() {
101 |         cm.operation(function() {
102 |           for (var i = 0; i < marks.length; i++) marks[i].clear();
103 |         });
104 |       };
105 |       if (autoclear) setTimeout(clear, 800);
106 |       else return clear;
107 |     }
108 |   }
109 | 
110 |   function doMatchBrackets(cm) {
111 |     cm.operation(function() {
112 |       if (cm.state.matchBrackets.currentlyHighlighted) {
113 |         cm.state.matchBrackets.currentlyHighlighted();
114 |         cm.state.matchBrackets.currentlyHighlighted = null;
115 |       }
116 |       cm.state.matchBrackets.currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets);
117 |     });
118 |   }
119 | 
120 |   CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) {
121 |     if (old && old != CodeMirror.Init) {
122 |       cm.off("cursorActivity", doMatchBrackets);
123 |       if (cm.state.matchBrackets && cm.state.matchBrackets.currentlyHighlighted) {
124 |         cm.state.matchBrackets.currentlyHighlighted();
125 |         cm.state.matchBrackets.currentlyHighlighted = null;
126 |       }
127 |     }
128 |     if (val) {
129 |       cm.state.matchBrackets = typeof val == "object" ? val : {};
130 |       cm.on("cursorActivity", doMatchBrackets);
131 |     }
132 |   });
133 | 
134 |   CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);});
135 |   CodeMirror.defineExtension("findMatchingBracket", function(pos, config, oldConfig){
136 |     // Backwards-compatibility kludge
137 |     if (oldConfig || typeof config == "boolean") {
138 |       if (!oldConfig) {
139 |         config = config ? {strict: true} : null
140 |       } else {
141 |         oldConfig.strict = config
142 |         config = oldConfig
143 |       }
144 |     }
145 |     return findMatchingBracket(this, pos, config)
146 |   });
147 |   CodeMirror.defineExtension("scanForBracket", function(pos, dir, style, config){
148 |     return scanForBracket(this, pos, dir, style, config);
149 |   });
150 | });
151 | 


--------------------------------------------------------------------------------
/hadui/web/vendor/cm/addon/edit/matchtags.js:
--------------------------------------------------------------------------------
 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
 2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
 3 | 
 4 | (function(mod) {
 5 |   if (typeof exports == "object" && typeof module == "object") // CommonJS
 6 |     mod(require("../../lib/codemirror"), require("../fold/xml-fold"));
 7 |   else if (typeof define == "function" && define.amd) // AMD
 8 |     define(["../../lib/codemirror", "../fold/xml-fold"], mod);
 9 |   else // Plain browser env
10 |     mod(CodeMirror);
11 | })(function(CodeMirror) {
12 |   "use strict";
13 | 
14 |   CodeMirror.defineOption("matchTags", false, function(cm, val, old) {
15 |     if (old && old != CodeMirror.Init) {
16 |       cm.off("cursorActivity", doMatchTags);
17 |       cm.off("viewportChange", maybeUpdateMatch);
18 |       clear(cm);
19 |     }
20 |     if (val) {
21 |       cm.state.matchBothTags = typeof val == "object" && val.bothTags;
22 |       cm.on("cursorActivity", doMatchTags);
23 |       cm.on("viewportChange", maybeUpdateMatch);
24 |       doMatchTags(cm);
25 |     }
26 |   });
27 | 
28 |   function clear(cm) {
29 |     if (cm.state.tagHit) cm.state.tagHit.clear();
30 |     if (cm.state.tagOther) cm.state.tagOther.clear();
31 |     cm.state.tagHit = cm.state.tagOther = null;
32 |   }
33 | 
34 |   function doMatchTags(cm) {
35 |     cm.state.failedTagMatch = false;
36 |     cm.operation(function() {
37 |       clear(cm);
38 |       if (cm.somethingSelected()) return;
39 |       var cur = cm.getCursor(), range = cm.getViewport();
40 |       range.from = Math.min(range.from, cur.line); range.to = Math.max(cur.line + 1, range.to);
41 |       var match = CodeMirror.findMatchingTag(cm, cur, range);
42 |       if (!match) return;
43 |       if (cm.state.matchBothTags) {
44 |         var hit = match.at == "open" ? match.open : match.close;
45 |         if (hit) cm.state.tagHit = cm.markText(hit.from, hit.to, {className: "CodeMirror-matchingtag"});
46 |       }
47 |       var other = match.at == "close" ? match.open : match.close;
48 |       if (other)
49 |         cm.state.tagOther = cm.markText(other.from, other.to, {className: "CodeMirror-matchingtag"});
50 |       else
51 |         cm.state.failedTagMatch = true;
52 |     });
53 |   }
54 | 
55 |   function maybeUpdateMatch(cm) {
56 |     if (cm.state.failedTagMatch) doMatchTags(cm);
57 |   }
58 | 
59 |   CodeMirror.commands.toMatchingTag = function(cm) {
60 |     var found = CodeMirror.findMatchingTag(cm, cm.getCursor());
61 |     if (found) {
62 |       var other = found.at == "close" ? found.open : found.close;
63 |       if (other) cm.extendSelection(other.to, other.from);
64 |     }
65 |   };
66 | });
67 | 


--------------------------------------------------------------------------------
/hadui/web/vendor/cm/addon/edit/trailingspace.js:
--------------------------------------------------------------------------------
 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
 2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
 3 | 
 4 | (function(mod) {
 5 |   if (typeof exports == "object" && typeof module == "object") // CommonJS
 6 |     mod(require("../../lib/codemirror"));
 7 |   else if (typeof define == "function" && define.amd) // AMD
 8 |     define(["../../lib/codemirror"], mod);
 9 |   else // Plain browser env
10 |     mod(CodeMirror);
11 | })(function(CodeMirror) {
12 |   CodeMirror.defineOption("showTrailingSpace", false, function(cm, val, prev) {
13 |     if (prev == CodeMirror.Init) prev = false;
14 |     if (prev && !val)
15 |       cm.removeOverlay("trailingspace");
16 |     else if (!prev && val)
17 |       cm.addOverlay({
18 |         token: function(stream) {
19 |           for (var l = stream.string.length, i = l; i && /\s/.test(stream.string.charAt(i - 1)); --i) {}
20 |           if (i > stream.pos) { stream.pos = i; return null; }
21 |           stream.pos = l;
22 |           return "trailingspace";
23 |         },
24 |         name: "trailingspace"
25 |       });
26 |   });
27 | });
28 | 


--------------------------------------------------------------------------------
/hadui/web/vendor/cm/addon/fold/brace-fold.js:
--------------------------------------------------------------------------------
  1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
  2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
  3 | 
  4 | (function(mod) {
  5 |   if (typeof exports == "object" && typeof module == "object") // CommonJS
  6 |     mod(require("../../lib/codemirror"));
  7 |   else if (typeof define == "function" && define.amd) // AMD
  8 |     define(["../../lib/codemirror"], mod);
  9 |   else // Plain browser env
 10 |     mod(CodeMirror);
 11 | })(function(CodeMirror) {
 12 | "use strict";
 13 | 
 14 | CodeMirror.registerHelper("fold", "brace", function(cm, start) {
 15 |   var line = start.line, lineText = cm.getLine(line);
 16 |   var tokenType;
 17 | 
 18 |   function findOpening(openCh) {
 19 |     for (var at = start.ch, pass = 0;;) {
 20 |       var found = at <= 0 ? -1 : lineText.lastIndexOf(openCh, at - 1);
 21 |       if (found == -1) {
 22 |         if (pass == 1) break;
 23 |         pass = 1;
 24 |         at = lineText.length;
 25 |         continue;
 26 |       }
 27 |       if (pass == 1 && found < start.ch) break;
 28 |       tokenType = cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1));
 29 |       if (!/^(comment|string)/.test(tokenType)) return found + 1;
 30 |       at = found - 1;
 31 |     }
 32 |   }
 33 | 
 34 |   var startToken = "{", endToken = "}", startCh = findOpening("{");
 35 |   if (startCh == null) {
 36 |     startToken = "[", endToken = "]";
 37 |     startCh = findOpening("[");
 38 |   }
 39 | 
 40 |   if (startCh == null) return;
 41 |   var count = 1, lastLine = cm.lastLine(), end, endCh;
 42 |   outer: for (var i = line; i <= lastLine; ++i) {
 43 |     var text = cm.getLine(i), pos = i == line ? startCh : 0;
 44 |     for (;;) {
 45 |       var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos);
 46 |       if (nextOpen < 0) nextOpen = text.length;
 47 |       if (nextClose < 0) nextClose = text.length;
 48 |       pos = Math.min(nextOpen, nextClose);
 49 |       if (pos == text.length) break;
 50 |       if (cm.getTokenTypeAt(CodeMirror.Pos(i, pos + 1)) == tokenType) {
 51 |         if (pos == nextOpen) ++count;
 52 |         else if (!--count) { end = i; endCh = pos; break outer; }
 53 |       }
 54 |       ++pos;
 55 |     }
 56 |   }
 57 |   if (end == null || line == end) return;
 58 |   return {from: CodeMirror.Pos(line, startCh),
 59 |           to: CodeMirror.Pos(end, endCh)};
 60 | });
 61 | 
 62 | CodeMirror.registerHelper("fold", "import", function(cm, start) {
 63 |   function hasImport(line) {
 64 |     if (line < cm.firstLine() || line > cm.lastLine()) return null;
 65 |     var start = cm.getTokenAt(CodeMirror.Pos(line, 1));
 66 |     if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));
 67 |     if (start.type != "keyword" || start.string != "import") return null;
 68 |     // Now find closing semicolon, return its position
 69 |     for (var i = line, e = Math.min(cm.lastLine(), line + 10); i <= e; ++i) {
 70 |       var text = cm.getLine(i), semi = text.indexOf(";");
 71 |       if (semi != -1) return {startCh: start.end, end: CodeMirror.Pos(i, semi)};
 72 |     }
 73 |   }
 74 | 
 75 |   var startLine = start.line, has = hasImport(startLine), prev;
 76 |   if (!has || hasImport(startLine - 1) || ((prev = hasImport(startLine - 2)) && prev.end.line == startLine - 1))
 77 |     return null;
 78 |   for (var end = has.end;;) {
 79 |     var next = hasImport(end.line + 1);
 80 |     if (next == null) break;
 81 |     end = next.end;
 82 |   }
 83 |   return {from: cm.clipPos(CodeMirror.Pos(startLine, has.startCh + 1)), to: end};
 84 | });
 85 | 
 86 | CodeMirror.registerHelper("fold", "include", function(cm, start) {
 87 |   function hasInclude(line) {
 88 |     if (line < cm.firstLine() || line > cm.lastLine()) return null;
 89 |     var start = cm.getTokenAt(CodeMirror.Pos(line, 1));
 90 |     if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));
 91 |     if (start.type == "meta" && start.string.slice(0, 8) == "#include") return start.start + 8;
 92 |   }
 93 | 
 94 |   var startLine = start.line, has = hasInclude(startLine);
 95 |   if (has == null || hasInclude(startLine - 1) != null) return null;
 96 |   for (var end = startLine;;) {
 97 |     var next = hasInclude(end + 1);
 98 |     if (next == null) break;
 99 |     ++end;
100 |   }
101 |   return {from: CodeMirror.Pos(startLine, has + 1),
102 |           to: cm.clipPos(CodeMirror.Pos(end))};
103 | });
104 | 
105 | });
106 | 


--------------------------------------------------------------------------------
/hadui/web/vendor/cm/addon/fold/comment-fold.js:
--------------------------------------------------------------------------------
 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
 2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
 3 | 
 4 | (function(mod) {
 5 |   if (typeof exports == "object" && typeof module == "object") // CommonJS
 6 |     mod(require("../../lib/codemirror"));
 7 |   else if (typeof define == "function" && define.amd) // AMD
 8 |     define(["../../lib/codemirror"], mod);
 9 |   else // Plain browser env
10 |     mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 | 
14 | CodeMirror.registerGlobalHelper("fold", "comment", function(mode) {
15 |   return mode.blockCommentStart && mode.blockCommentEnd;
16 | }, function(cm, start) {
17 |   var mode = cm.getModeAt(start), startToken = mode.blockCommentStart, endToken = mode.blockCommentEnd;
18 |   if (!startToken || !endToken) return;
19 |   var line = start.line, lineText = cm.getLine(line);
20 | 
21 |   var startCh;
22 |   for (var at = start.ch, pass = 0;;) {
23 |     var found = at <= 0 ? -1 : lineText.lastIndexOf(startToken, at - 1);
24 |     if (found == -1) {
25 |       if (pass == 1) return;
26 |       pass = 1;
27 |       at = lineText.length;
28 |       continue;
29 |     }
30 |     if (pass == 1 && found < start.ch) return;
31 |     if (/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1))) &&
32 |         (found == 0 || lineText.slice(found - endToken.length, found) == endToken ||
33 |          !/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found))))) {
34 |       startCh = found + startToken.length;
35 |       break;
36 |     }
37 |     at = found - 1;
38 |   }
39 | 
40 |   var depth = 1, lastLine = cm.lastLine(), end, endCh;
41 |   outer: for (var i = line; i <= lastLine; ++i) {
42 |     var text = cm.getLine(i), pos = i == line ? startCh : 0;
43 |     for (;;) {
44 |       var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos);
45 |       if (nextOpen < 0) nextOpen = text.length;
46 |       if (nextClose < 0) nextClose = text.length;
47 |       pos = Math.min(nextOpen, nextClose);
48 |       if (pos == text.length) break;
49 |       if (pos == nextOpen) ++depth;
50 |       else if (!--depth) { end = i; endCh = pos; break outer; }
51 |       ++pos;
52 |     }
53 |   }
54 |   if (end == null || line == end && endCh == startCh) return;
55 |   return {from: CodeMirror.Pos(line, startCh),
56 |           to: CodeMirror.Pos(end, endCh)};
57 | });
58 | 
59 | });
60 | 


--------------------------------------------------------------------------------
/hadui/web/vendor/cm/addon/fold/foldcode.js:
--------------------------------------------------------------------------------
  1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
  2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
  3 | 
  4 | (function(mod) {
  5 |   if (typeof exports == "object" && typeof module == "object") // CommonJS
  6 |     mod(require("../../lib/codemirror"));
  7 |   else if (typeof define == "function" && define.amd) // AMD
  8 |     define(["../../lib/codemirror"], mod);
  9 |   else // Plain browser env
 10 |     mod(CodeMirror);
 11 | })(function(CodeMirror) {
 12 |   "use strict";
 13 | 
 14 |   function doFold(cm, pos, options, force) {
 15 |     if (options && options.call) {
 16 |       var finder = options;
 17 |       options = null;
 18 |     } else {
 19 |       var finder = getOption(cm, options, "rangeFinder");
 20 |     }
 21 |     if (typeof pos == "number") pos = CodeMirror.Pos(pos, 0);
 22 |     var minSize = getOption(cm, options, "minFoldSize");
 23 | 
 24 |     function getRange(allowFolded) {
 25 |       var range = finder(cm, pos);
 26 |       if (!range || range.to.line - range.from.line < minSize) return null;
 27 |       var marks = cm.findMarksAt(range.from);
 28 |       for (var i = 0; i < marks.length; ++i) {
 29 |         if (marks[i].__isFold && force !== "fold") {
 30 |           if (!allowFolded) return null;
 31 |           range.cleared = true;
 32 |           marks[i].clear();
 33 |         }
 34 |       }
 35 |       return range;
 36 |     }
 37 | 
 38 |     var range = getRange(true);
 39 |     if (getOption(cm, options, "scanUp")) while (!range && pos.line > cm.firstLine()) {
 40 |       pos = CodeMirror.Pos(pos.line - 1, 0);
 41 |       range = getRange(false);
 42 |     }
 43 |     if (!range || range.cleared || force === "unfold") return;
 44 | 
 45 |     var myWidget = makeWidget(cm, options);
 46 |     CodeMirror.on(myWidget, "mousedown", function(e) {
 47 |       myRange.clear();
 48 |       CodeMirror.e_preventDefault(e);
 49 |     });
 50 |     var myRange = cm.markText(range.from, range.to, {
 51 |       replacedWith: myWidget,
 52 |       clearOnEnter: getOption(cm, options, "clearOnEnter"),
 53 |       __isFold: true
 54 |     });
 55 |     myRange.on("clear", function(from, to) {
 56 |       CodeMirror.signal(cm, "unfold", cm, from, to);
 57 |     });
 58 |     CodeMirror.signal(cm, "fold", cm, range.from, range.to);
 59 |   }
 60 | 
 61 |   function makeWidget(cm, options) {
 62 |     var widget = getOption(cm, options, "widget");
 63 |     if (typeof widget == "string") {
 64 |       var text = document.createTextNode(widget);
 65 |       widget = document.createElement("span");
 66 |       widget.appendChild(text);
 67 |       widget.className = "CodeMirror-foldmarker";
 68 |     } else if (widget) {
 69 |       widget = widget.cloneNode(true)
 70 |     }
 71 |     return widget;
 72 |   }
 73 | 
 74 |   // Clumsy backwards-compatible interface
 75 |   CodeMirror.newFoldFunction = function(rangeFinder, widget) {
 76 |     return function(cm, pos) { doFold(cm, pos, {rangeFinder: rangeFinder, widget: widget}); };
 77 |   };
 78 | 
 79 |   // New-style interface
 80 |   CodeMirror.defineExtension("foldCode", function(pos, options, force) {
 81 |     doFold(this, pos, options, force);
 82 |   });
 83 | 
 84 |   CodeMirror.defineExtension("isFolded", function(pos) {
 85 |     var marks = this.findMarksAt(pos);
 86 |     for (var i = 0; i < marks.length; ++i)
 87 |       if (marks[i].__isFold) return true;
 88 |   });
 89 | 
 90 |   CodeMirror.commands.toggleFold = function(cm) {
 91 |     cm.foldCode(cm.getCursor());
 92 |   };
 93 |   CodeMirror.commands.fold = function(cm) {
 94 |     cm.foldCode(cm.getCursor(), null, "fold");
 95 |   };
 96 |   CodeMirror.commands.unfold = function(cm) {
 97 |     cm.foldCode(cm.getCursor(), null, "unfold");
 98 |   };
 99 |   CodeMirror.commands.foldAll = function(cm) {
100 |     cm.operation(function() {
101 |       for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++)
102 |         cm.foldCode(CodeMirror.Pos(i, 0), null, "fold");
103 |     });
104 |   };
105 |   CodeMirror.commands.unfoldAll = function(cm) {
106 |     cm.operation(function() {
107 |       for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++)
108 |         cm.foldCode(CodeMirror.Pos(i, 0), null, "unfold");
109 |     });
110 |   };
111 | 
112 |   CodeMirror.registerHelper("fold", "combine", function() {
113 |     var funcs = Array.prototype.slice.call(arguments, 0);
114 |     return function(cm, start) {
115 |       for (var i = 0; i < funcs.length; ++i) {
116 |         var found = funcs[i](cm, start);
117 |         if (found) return found;
118 |       }
119 |     };
120 |   });
121 | 
122 |   CodeMirror.registerHelper("fold", "auto", function(cm, start) {
123 |     var helpers = cm.getHelpers(start, "fold");
124 |     for (var i = 0; i < helpers.length; i++) {
125 |       var cur = helpers[i](cm, start);
126 |       if (cur) return cur;
127 |     }
128 |   });
129 | 
130 |   var defaultOptions = {
131 |     rangeFinder: CodeMirror.fold.auto,
132 |     widget: "\u2194",
133 |     minFoldSize: 0,
134 |     scanUp: false,
135 |     clearOnEnter: true
136 |   };
137 | 
138 |   CodeMirror.defineOption("foldOptions", null);
139 | 
140 |   function getOption(cm, options, name) {
141 |     if (options && options[name] !== undefined)
142 |       return options[name];
143 |     var editorOptions = cm.options.foldOptions;
144 |     if (editorOptions && editorOptions[name] !== undefined)
145 |       return editorOptions[name];
146 |     return defaultOptions[name];
147 |   }
148 | 
149 |   CodeMirror.defineExtension("foldOption", function(options, name) {
150 |     return getOption(this, options, name);
151 |   });
152 | });
153 | 


--------------------------------------------------------------------------------
/hadui/web/vendor/cm/addon/fold/foldgutter.css:
--------------------------------------------------------------------------------
 1 | .CodeMirror-foldmarker {
 2 |   color: blue;
 3 |   text-shadow: #b9f 1px 1px 2px, #b9f -1px -1px 2px, #b9f 1px -1px 2px, #b9f -1px 1px 2px;
 4 |   font-family: arial;
 5 |   line-height: .3;
 6 |   cursor: pointer;
 7 | }
 8 | .CodeMirror-foldgutter {
 9 |   width: .7em;
10 | }
11 | .CodeMirror-foldgutter-open,
12 | .CodeMirror-foldgutter-folded {
13 |   cursor: pointer;
14 | }
15 | .CodeMirror-foldgutter-open:after {
16 |   content: "\25BE";
17 | }
18 | .CodeMirror-foldgutter-folded:after {
19 |   content: "\25B8";
20 | }
21 | 


--------------------------------------------------------------------------------
/hadui/web/vendor/cm/addon/fold/foldgutter.js:
--------------------------------------------------------------------------------
  1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
  2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
  3 | 
  4 | (function(mod) {
  5 |   if (typeof exports == "object" && typeof module == "object") // CommonJS
  6 |     mod(require("../../lib/codemirror"), require("./foldcode"));
  7 |   else if (typeof define == "function" && define.amd) // AMD
  8 |     define(["../../lib/codemirror", "./foldcode"], mod);
  9 |   else // Plain browser env
 10 |     mod(CodeMirror);
 11 | })(function(CodeMirror) {
 12 |   "use strict";
 13 | 
 14 |   CodeMirror.defineOption("foldGutter", false, function(cm, val, old) {
 15 |     if (old && old != CodeMirror.Init) {
 16 |       cm.clearGutter(cm.state.foldGutter.options.gutter);
 17 |       cm.state.foldGutter = null;
 18 |       cm.off("gutterClick", onGutterClick);
 19 |       cm.off("changes", onChange);
 20 |       cm.off("viewportChange", onViewportChange);
 21 |       cm.off("fold", onFold);
 22 |       cm.off("unfold", onFold);
 23 |       cm.off("swapDoc", onChange);
 24 |     }
 25 |     if (val) {
 26 |       cm.state.foldGutter = new State(parseOptions(val));
 27 |       updateInViewport(cm);
 28 |       cm.on("gutterClick", onGutterClick);
 29 |       cm.on("changes", onChange);
 30 |       cm.on("viewportChange", onViewportChange);
 31 |       cm.on("fold", onFold);
 32 |       cm.on("unfold", onFold);
 33 |       cm.on("swapDoc", onChange);
 34 |     }
 35 |   });
 36 | 
 37 |   var Pos = CodeMirror.Pos;
 38 | 
 39 |   function State(options) {
 40 |     this.options = options;
 41 |     this.from = this.to = 0;
 42 |   }
 43 | 
 44 |   function parseOptions(opts) {
 45 |     if (opts === true) opts = {};
 46 |     if (opts.gutter == null) opts.gutter = "CodeMirror-foldgutter";
 47 |     if (opts.indicatorOpen == null) opts.indicatorOpen = "CodeMirror-foldgutter-open";
 48 |     if (opts.indicatorFolded == null) opts.indicatorFolded = "CodeMirror-foldgutter-folded";
 49 |     return opts;
 50 |   }
 51 | 
 52 |   function isFolded(cm, line) {
 53 |     var marks = cm.findMarks(Pos(line, 0), Pos(line + 1, 0));
 54 |     for (var i = 0; i < marks.length; ++i) {
 55 |       if (marks[i].__isFold) {
 56 |         var fromPos = marks[i].find(-1);
 57 |         if (fromPos && fromPos.line === line)
 58 |           return marks[i];
 59 |       }
 60 |     }
 61 |   }
 62 | 
 63 |   function marker(spec) {
 64 |     if (typeof spec == "string") {
 65 |       var elt = document.createElement("div");
 66 |       elt.className = spec + " CodeMirror-guttermarker-subtle";
 67 |       return elt;
 68 |     } else {
 69 |       return spec.cloneNode(true);
 70 |     }
 71 |   }
 72 | 
 73 |   function updateFoldInfo(cm, from, to) {
 74 |     var opts = cm.state.foldGutter.options, cur = from - 1;
 75 |     var minSize = cm.foldOption(opts, "minFoldSize");
 76 |     var func = cm.foldOption(opts, "rangeFinder");
 77 |     // we can reuse the built-in indicator element if its className matches the new state
 78 |     var clsFolded = typeof opts.indicatorFolded == "string" && classTest(opts.indicatorFolded);
 79 |     var clsOpen = typeof opts.indicatorOpen == "string" && classTest(opts.indicatorOpen);
 80 |     cm.eachLine(from, to, function(line) {
 81 |       ++cur;
 82 |       var mark = null;
 83 |       var old = line.gutterMarkers;
 84 |       if (old) old = old[opts.gutter];
 85 |       if (isFolded(cm, cur)) {
 86 |         if (clsFolded && old && clsFolded.test(old.className)) return;
 87 |         mark = marker(opts.indicatorFolded);
 88 |       } else {
 89 |         var pos = Pos(cur, 0);
 90 |         var range = func && func(cm, pos);
 91 |         if (range && range.to.line - range.from.line >= minSize) {
 92 |           if (clsOpen && old && clsOpen.test(old.className)) return;
 93 |           mark = marker(opts.indicatorOpen);
 94 |         }
 95 |       }
 96 |       if (!mark && !old) return;
 97 |       cm.setGutterMarker(line, opts.gutter, mark);
 98 |     });
 99 |   }
100 | 
101 |   // copied from CodeMirror/src/util/dom.js
102 |   function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*") }
103 | 
104 |   function updateInViewport(cm) {
105 |     var vp = cm.getViewport(), state = cm.state.foldGutter;
106 |     if (!state) return;
107 |     cm.operation(function() {
108 |       updateFoldInfo(cm, vp.from, vp.to);
109 |     });
110 |     state.from = vp.from; state.to = vp.to;
111 |   }
112 | 
113 |   function onGutterClick(cm, line, gutter) {
114 |     var state = cm.state.foldGutter;
115 |     if (!state) return;
116 |     var opts = state.options;
117 |     if (gutter != opts.gutter) return;
118 |     var folded = isFolded(cm, line);
119 |     if (folded) folded.clear();
120 |     else cm.foldCode(Pos(line, 0), opts);
121 |   }
122 | 
123 |   function onChange(cm) {
124 |     var state = cm.state.foldGutter;
125 |     if (!state) return;
126 |     var opts = state.options;
127 |     state.from = state.to = 0;
128 |     clearTimeout(state.changeUpdate);
129 |     state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, opts.foldOnChangeTimeSpan || 600);
130 |   }
131 | 
132 |   function onViewportChange(cm) {
133 |     var state = cm.state.foldGutter;
134 |     if (!state) return;
135 |     var opts = state.options;
136 |     clearTimeout(state.changeUpdate);
137 |     state.changeUpdate = setTimeout(function() {
138 |       var vp = cm.getViewport();
139 |       if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) {
140 |         updateInViewport(cm);
141 |       } else {
142 |         cm.operation(function() {
143 |           if (vp.from < state.from) {
144 |             updateFoldInfo(cm, vp.from, state.from);
145 |             state.from = vp.from;
146 |           }
147 |           if (vp.to > state.to) {
148 |             updateFoldInfo(cm, state.to, vp.to);
149 |             state.to = vp.to;
150 |           }
151 |         });
152 |       }
153 |     }, opts.updateViewportTimeSpan || 400);
154 |   }
155 | 
156 |   function onFold(cm, from) {
157 |     var state = cm.state.foldGutter;
158 |     if (!state) return;
159 |     var line = from.line;
160 |     if (line >= state.from && line < state.to)
161 |       updateFoldInfo(cm, line, line + 1);
162 |   }
163 | });
164 | 


--------------------------------------------------------------------------------
/hadui/web/vendor/cm/addon/fold/indent-fold.js:
--------------------------------------------------------------------------------
 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
 2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
 3 | 
 4 | (function(mod) {
 5 |   if (typeof exports == "object" && typeof module == "object") // CommonJS
 6 |     mod(require("../../lib/codemirror"));
 7 |   else if (typeof define == "function" && define.amd) // AMD
 8 |     define(["../../lib/codemirror"], mod);
 9 |   else // Plain browser env
10 |     mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 | 
14 | function lineIndent(cm, lineNo) {
15 |   var text = cm.getLine(lineNo)
16 |   var spaceTo = text.search(/\S/)
17 |   if (spaceTo == -1 || /\bcomment\b/.test(cm.getTokenTypeAt(CodeMirror.Pos(lineNo, spaceTo + 1))))
18 |     return -1
19 |   return CodeMirror.countColumn(text, null, cm.getOption("tabSize"))
20 | }
21 | 
22 | CodeMirror.registerHelper("fold", "indent", function(cm, start) {
23 |   var myIndent = lineIndent(cm, start.line)
24 |   if (myIndent < 0) return
25 |   var lastLineInFold = null
26 | 
27 |   // Go through lines until we find a line that definitely doesn't belong in
28 |   // the block we're folding, or to the end.
29 |   for (var i = start.line + 1, end = cm.lastLine(); i <= end; ++i) {
30 |     var indent = lineIndent(cm, i)
31 |     if (indent == -1) {
32 |     } else if (indent > myIndent) {
33 |       // Lines with a greater indent are considered part of the block.
34 |       lastLineInFold = i;
35 |     } else {
36 |       // If this line has non-space, non-comment content, and is
37 |       // indented less or equal to the start line, it is the start of
38 |       // another block.
39 |       break;
40 |     }
41 |   }
42 |   if (lastLineInFold) return {
43 |     from: CodeMirror.Pos(start.line, cm.getLine(start.line).length),
44 |     to: CodeMirror.Pos(lastLineInFold, cm.getLine(lastLineInFold).length)
45 |   };
46 | });
47 | 
48 | });
49 | 


--------------------------------------------------------------------------------
/hadui/web/vendor/cm/addon/fold/markdown-fold.js:
--------------------------------------------------------------------------------
 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
 2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
 3 | 
 4 | (function(mod) {
 5 |   if (typeof exports == "object" && typeof module == "object") // CommonJS
 6 |     mod(require("../../lib/codemirror"));
 7 |   else if (typeof define == "function" && define.amd) // AMD
 8 |     define(["../../lib/codemirror"], mod);
 9 |   else // Plain browser env
10 |     mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 | 
14 | CodeMirror.registerHelper("fold", "markdown", function(cm, start) {
15 |   var maxDepth = 100;
16 | 
17 |   function isHeader(lineNo) {
18 |     var tokentype = cm.getTokenTypeAt(CodeMirror.Pos(lineNo, 0));
19 |     return tokentype && /\bheader\b/.test(tokentype);
20 |   }
21 | 
22 |   function headerLevel(lineNo, line, nextLine) {
23 |     var match = line && line.match(/^#+/);
24 |     if (match && isHeader(lineNo)) return match[0].length;
25 |     match = nextLine && nextLine.match(/^[=\-]+\s*$/);
26 |     if (match && isHeader(lineNo + 1)) return nextLine[0] == "=" ? 1 : 2;
27 |     return maxDepth;
28 |   }
29 | 
30 |   var firstLine = cm.getLine(start.line), nextLine = cm.getLine(start.line + 1);
31 |   var level = headerLevel(start.line, firstLine, nextLine);
32 |   if (level === maxDepth) return undefined;
33 | 
34 |   var lastLineNo = cm.lastLine();
35 |   var end = start.line, nextNextLine = cm.getLine(end + 2);
36 |   while (end < lastLineNo) {
37 |     if (headerLevel(end + 1, nextLine, nextNextLine) <= level) break;
38 |     ++end;
39 |     nextLine = nextNextLine;
40 |     nextNextLine = cm.getLine(end + 2);
41 |   }
42 | 
43 |   return {
44 |     from: CodeMirror.Pos(start.line, firstLine.length),
45 |     to: CodeMirror.Pos(end, cm.getLine(end).length)
46 |   };
47 | });
48 | 
49 | });
50 | 


--------------------------------------------------------------------------------
/hadui/web/vendor/cm/addon/fold/xml-fold.js:
--------------------------------------------------------------------------------
  1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
  2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
  3 | 
  4 | (function(mod) {
  5 |   if (typeof exports == "object" && typeof module == "object") // CommonJS
  6 |     mod(require("../../lib/codemirror"));
  7 |   else if (typeof define == "function" && define.amd) // AMD
  8 |     define(["../../lib/codemirror"], mod);
  9 |   else // Plain browser env
 10 |     mod(CodeMirror);
 11 | })(function(CodeMirror) {
 12 |   "use strict";
 13 | 
 14 |   var Pos = CodeMirror.Pos;
 15 |   function cmp(a, b) { return a.line - b.line || a.ch - b.ch; }
 16 | 
 17 |   var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD";
 18 |   var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040";
 19 |   var xmlTagStart = new RegExp("<(/?)([" + nameStartChar + "][" + nameChar + "]*)", "g");
 20 | 
 21 |   function Iter(cm, line, ch, range) {
 22 |     this.line = line; this.ch = ch;
 23 |     this.cm = cm; this.text = cm.getLine(line);
 24 |     this.min = range ? Math.max(range.from, cm.firstLine()) : cm.firstLine();
 25 |     this.max = range ? Math.min(range.to - 1, cm.lastLine()) : cm.lastLine();
 26 |   }
 27 | 
 28 |   function tagAt(iter, ch) {
 29 |     var type = iter.cm.getTokenTypeAt(Pos(iter.line, ch));
 30 |     return type && /\btag\b/.test(type);
 31 |   }
 32 | 
 33 |   function nextLine(iter) {
 34 |     if (iter.line >= iter.max) return;
 35 |     iter.ch = 0;
 36 |     iter.text = iter.cm.getLine(++iter.line);
 37 |     return true;
 38 |   }
 39 |   function prevLine(iter) {
 40 |     if (iter.line <= iter.min) return;
 41 |     iter.text = iter.cm.getLine(--iter.line);
 42 |     iter.ch = iter.text.length;
 43 |     return true;
 44 |   }
 45 | 
 46 |   function toTagEnd(iter) {
 47 |     for (;;) {
 48 |       var gt = iter.text.indexOf(">", iter.ch);
 49 |       if (gt == -1) { if (nextLine(iter)) continue; else return; }
 50 |       if (!tagAt(iter, gt + 1)) { iter.ch = gt + 1; continue; }
 51 |       var lastSlash = iter.text.lastIndexOf("/", gt);
 52 |       var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt));
 53 |       iter.ch = gt + 1;
 54 |       return selfClose ? "selfClose" : "regular";
 55 |     }
 56 |   }
 57 |   function toTagStart(iter) {
 58 |     for (;;) {
 59 |       var lt = iter.ch ? iter.text.lastIndexOf("<", iter.ch - 1) : -1;
 60 |       if (lt == -1) { if (prevLine(iter)) continue; else return; }
 61 |       if (!tagAt(iter, lt + 1)) { iter.ch = lt; continue; }
 62 |       xmlTagStart.lastIndex = lt;
 63 |       iter.ch = lt;
 64 |       var match = xmlTagStart.exec(iter.text);
 65 |       if (match && match.index == lt) return match;
 66 |     }
 67 |   }
 68 | 
 69 |   function toNextTag(iter) {
 70 |     for (;;) {
 71 |       xmlTagStart.lastIndex = iter.ch;
 72 |       var found = xmlTagStart.exec(iter.text);
 73 |       if (!found) { if (nextLine(iter)) continue; else return; }
 74 |       if (!tagAt(iter, found.index + 1)) { iter.ch = found.index + 1; continue; }
 75 |       iter.ch = found.index + found[0].length;
 76 |       return found;
 77 |     }
 78 |   }
 79 |   function toPrevTag(iter) {
 80 |     for (;;) {
 81 |       var gt = iter.ch ? iter.text.lastIndexOf(">", iter.ch - 1) : -1;
 82 |       if (gt == -1) { if (prevLine(iter)) continue; else return; }
 83 |       if (!tagAt(iter, gt + 1)) { iter.ch = gt; continue; }
 84 |       var lastSlash = iter.text.lastIndexOf("/", gt);
 85 |       var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt));
 86 |       iter.ch = gt + 1;
 87 |       return selfClose ? "selfClose" : "regular";
 88 |     }
 89 |   }
 90 | 
 91 |   function findMatchingClose(iter, tag) {
 92 |     var stack = [];
 93 |     for (;;) {
 94 |       var next = toNextTag(iter), end, startLine = iter.line, startCh = iter.ch - (next ? next[0].length : 0);
 95 |       if (!next || !(end = toTagEnd(iter))) return;
 96 |       if (end == "selfClose") continue;
 97 |       if (next[1]) { // closing tag
 98 |         for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == next[2]) {
 99 |           stack.length = i;
100 |           break;
101 |         }
102 |         if (i < 0 && (!tag || tag == next[2])) return {
103 |           tag: next[2],
104 |           from: Pos(startLine, startCh),
105 |           to: Pos(iter.line, iter.ch)
106 |         };
107 |       } else { // opening tag
108 |         stack.push(next[2]);
109 |       }
110 |     }
111 |   }
112 |   function findMatchingOpen(iter, tag) {
113 |     var stack = [];
114 |     for (;;) {
115 |       var prev = toPrevTag(iter);
116 |       if (!prev) return;
117 |       if (prev == "selfClose") { toTagStart(iter); continue; }
118 |       var endLine = iter.line, endCh = iter.ch;
119 |       var start = toTagStart(iter);
120 |       if (!start) return;
121 |       if (start[1]) { // closing tag
122 |         stack.push(start[2]);
123 |       } else { // opening tag
124 |         for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == start[2]) {
125 |           stack.length = i;
126 |           break;
127 |         }
128 |         if (i < 0 && (!tag || tag == start[2])) return {
129 |           tag: start[2],
130 |           from: Pos(iter.line, iter.ch),
131 |           to: Pos(endLine, endCh)
132 |         };
133 |       }
134 |     }
135 |   }
136 | 
137 |   CodeMirror.registerHelper("fold", "xml", function(cm, start) {
138 |     var iter = new Iter(cm, start.line, 0);
139 |     for (;;) {
140 |       var openTag = toNextTag(iter)
141 |       if (!openTag || iter.line != start.line) return
142 |       var end = toTagEnd(iter)
143 |       if (!end) return
144 |       if (!openTag[1] && end != "selfClose") {
145 |         var startPos = Pos(iter.line, iter.ch);
146 |         var endPos = findMatchingClose(iter, openTag[2]);
147 |         return endPos && cmp(endPos.from, startPos) > 0 ? {from: startPos, to: endPos.from} : null
148 |       }
149 |     }
150 |   });
151 |   CodeMirror.findMatchingTag = function(cm, pos, range) {
152 |     var iter = new Iter(cm, pos.line, pos.ch, range);
153 |     if (iter.text.indexOf(">") == -1 && iter.text.indexOf("<") == -1) return;
154 |     var end = toTagEnd(iter), to = end && Pos(iter.line, iter.ch);
155 |     var start = end && toTagStart(iter);
156 |     if (!end || !start || cmp(iter, pos) > 0) return;
157 |     var here = {from: Pos(iter.line, iter.ch), to: to, tag: start[2]};
158 |     if (end == "selfClose") return {open: here, close: null, at: "open"};
159 | 
160 |     if (start[1]) { // closing tag
161 |       return {open: findMatchingOpen(iter, start[2]), close: here, at: "close"};
162 |     } else { // opening tag
163 |       iter = new Iter(cm, to.line, to.ch, range);
164 |       return {open: here, close: findMatchingClose(iter, start[2]), at: "open"};
165 |     }
166 |   };
167 | 
168 |   CodeMirror.findEnclosingTag = function(cm, pos, range, tag) {
169 |     var iter = new Iter(cm, pos.line, pos.ch, range);
170 |     for (;;) {
171 |       var open = findMatchingOpen(iter, tag);
172 |       if (!open) break;
173 |       var forward = new Iter(cm, pos.line, pos.ch, range);
174 |       var close = findMatchingClose(forward, open.tag);
175 |       if (close) return {open: open, close: close};
176 |     }
177 |   };
178 | 
179 |   // Used by addon/edit/closetag.js
180 |   CodeMirror.scanForClosingTag = function(cm, pos, name, end) {
181 |     var iter = new Iter(cm, pos.line, pos.ch, end ? {from: 0, to: end} : null);
182 |     return findMatchingClose(iter, name);
183 |   };
184 | });
185 | 


--------------------------------------------------------------------------------
/hadui/web/vendor/cm/addon/search/jump-to-line.js:
--------------------------------------------------------------------------------
 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
 2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
 3 | 
 4 | // Defines jumpToLine command. Uses dialog.js if present.
 5 | 
 6 | (function(mod) {
 7 |   if (typeof exports == "object" && typeof module == "object") // CommonJS
 8 |     mod(require("../../lib/codemirror"), require("../dialog/dialog"));
 9 |   else if (typeof define == "function" && define.amd) // AMD
10 |     define(["../../lib/codemirror", "../dialog/dialog"], mod);
11 |   else // Plain browser env
12 |     mod(CodeMirror);
13 | })(function(CodeMirror) {
14 |   "use strict";
15 | 
16 |   function dialog(cm, text, shortText, deflt, f) {
17 |     if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true});
18 |     else f(prompt(shortText, deflt));
19 |   }
20 | 
21 |   function getJumpDialog(cm) {
22 |     return cm.phrase("Jump to line:") + '  ' + cm.phrase("(Use line:column or scroll% syntax)") + '';
23 |   }
24 | 
25 |   function interpretLine(cm, string) {
26 |     var num = Number(string)
27 |     if (/^[-+]/.test(string)) return cm.getCursor().line + num
28 |     else return num - 1
29 |   }
30 | 
31 |   CodeMirror.commands.jumpToLine = function(cm) {
32 |     var cur = cm.getCursor();
33 |     dialog(cm, getJumpDialog(cm), cm.phrase("Jump to line:"), (cur.line + 1) + ":" + cur.ch, function(posStr) {
34 |       if (!posStr) return;
35 | 
36 |       var match;
37 |       if (match = /^\s*([\+\-]?\d+)\s*\:\s*(\d+)\s*$/.exec(posStr)) {
38 |         cm.setCursor(interpretLine(cm, match[1]), Number(match[2]))
39 |       } else if (match = /^\s*([\+\-]?\d+(\.\d+)?)\%\s*/.exec(posStr)) {
40 |         var line = Math.round(cm.lineCount() * Number(match[1]) / 100);
41 |         if (/^[-+]/.test(match[1])) line = cur.line + line + 1;
42 |         cm.setCursor(line - 1, cur.ch);
43 |       } else if (match = /^\s*\:?\s*([\+\-]?\d+)\s*/.exec(posStr)) {
44 |         cm.setCursor(interpretLine(cm, match[1]), cur.ch);
45 |       }
46 |     });
47 |   };
48 | 
49 |   CodeMirror.keyMap["default"]["Alt-G"] = "jumpToLine";
50 | });
51 | 


--------------------------------------------------------------------------------
/hadui/web/vendor/cm/addon/search/match-highlighter.js:
--------------------------------------------------------------------------------
  1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
  2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
  3 | 
  4 | // Highlighting text that matches the selection
  5 | //
  6 | // Defines an option highlightSelectionMatches, which, when enabled,
  7 | // will style strings that match the selection throughout the
  8 | // document.
  9 | //
 10 | // The option can be set to true to simply enable it, or to a
 11 | // {minChars, style, wordsOnly, showToken, delay} object to explicitly
 12 | // configure it. minChars is the minimum amount of characters that should be
 13 | // selected for the behavior to occur, and style is the token style to
 14 | // apply to the matches. This will be prefixed by "cm-" to create an
 15 | // actual CSS class name. If wordsOnly is enabled, the matches will be
 16 | // highlighted only if the selected text is a word. showToken, when enabled,
 17 | // will cause the current token to be highlighted when nothing is selected.
 18 | // delay is used to specify how much time to wait, in milliseconds, before
 19 | // highlighting the matches. If annotateScrollbar is enabled, the occurences
 20 | // will be highlighted on the scrollbar via the matchesonscrollbar addon.
 21 | 
 22 | (function(mod) {
 23 |   if (typeof exports == "object" && typeof module == "object") // CommonJS
 24 |     mod(require("../../lib/codemirror"), require("./matchesonscrollbar"));
 25 |   else if (typeof define == "function" && define.amd) // AMD
 26 |     define(["../../lib/codemirror", "./matchesonscrollbar"], mod);
 27 |   else // Plain browser env
 28 |     mod(CodeMirror);
 29 | })(function(CodeMirror) {
 30 |   "use strict";
 31 | 
 32 |   var defaults = {
 33 |     style: "matchhighlight",
 34 |     minChars: 2,
 35 |     delay: 100,
 36 |     wordsOnly: false,
 37 |     annotateScrollbar: false,
 38 |     showToken: false,
 39 |     trim: true
 40 |   }
 41 | 
 42 |   function State(options) {
 43 |     this.options = {}
 44 |     for (var name in defaults)
 45 |       this.options[name] = (options && options.hasOwnProperty(name) ? options : defaults)[name]
 46 |     this.overlay = this.timeout = null;
 47 |     this.matchesonscroll = null;
 48 |     this.active = false;
 49 |   }
 50 | 
 51 |   CodeMirror.defineOption("highlightSelectionMatches", false, function(cm, val, old) {
 52 |     if (old && old != CodeMirror.Init) {
 53 |       removeOverlay(cm);
 54 |       clearTimeout(cm.state.matchHighlighter.timeout);
 55 |       cm.state.matchHighlighter = null;
 56 |       cm.off("cursorActivity", cursorActivity);
 57 |       cm.off("focus", onFocus)
 58 |     }
 59 |     if (val) {
 60 |       var state = cm.state.matchHighlighter = new State(val);
 61 |       if (cm.hasFocus()) {
 62 |         state.active = true
 63 |         highlightMatches(cm)
 64 |       } else {
 65 |         cm.on("focus", onFocus)
 66 |       }
 67 |       cm.on("cursorActivity", cursorActivity);
 68 |     }
 69 |   });
 70 | 
 71 |   function cursorActivity(cm) {
 72 |     var state = cm.state.matchHighlighter;
 73 |     if (state.active || cm.hasFocus()) scheduleHighlight(cm, state)
 74 |   }
 75 | 
 76 |   function onFocus(cm) {
 77 |     var state = cm.state.matchHighlighter
 78 |     if (!state.active) {
 79 |       state.active = true
 80 |       scheduleHighlight(cm, state)
 81 |     }
 82 |   }
 83 | 
 84 |   function scheduleHighlight(cm, state) {
 85 |     clearTimeout(state.timeout);
 86 |     state.timeout = setTimeout(function() {highlightMatches(cm);}, state.options.delay);
 87 |   }
 88 | 
 89 |   function addOverlay(cm, query, hasBoundary, style) {
 90 |     var state = cm.state.matchHighlighter;
 91 |     cm.addOverlay(state.overlay = makeOverlay(query, hasBoundary, style));
 92 |     if (state.options.annotateScrollbar && cm.showMatchesOnScrollbar) {
 93 |       var searchFor = hasBoundary ? new RegExp("\\b" + query.replace(/[\\\[.+*?(){|^$]/g, "\\$&") + "\\b") : query;
 94 |       state.matchesonscroll = cm.showMatchesOnScrollbar(searchFor, false,
 95 |         {className: "CodeMirror-selection-highlight-scrollbar"});
 96 |     }
 97 |   }
 98 | 
 99 |   function removeOverlay(cm) {
100 |     var state = cm.state.matchHighlighter;
101 |     if (state.overlay) {
102 |       cm.removeOverlay(state.overlay);
103 |       state.overlay = null;
104 |       if (state.matchesonscroll) {
105 |         state.matchesonscroll.clear();
106 |         state.matchesonscroll = null;
107 |       }
108 |     }
109 |   }
110 | 
111 |   function highlightMatches(cm) {
112 |     cm.operation(function() {
113 |       var state = cm.state.matchHighlighter;
114 |       removeOverlay(cm);
115 |       if (!cm.somethingSelected() && state.options.showToken) {
116 |         var re = state.options.showToken === true ? /[\w$]/ : state.options.showToken;
117 |         var cur = cm.getCursor(), line = cm.getLine(cur.line), start = cur.ch, end = start;
118 |         while (start && re.test(line.charAt(start - 1))) --start;
119 |         while (end < line.length && re.test(line.charAt(end))) ++end;
120 |         if (start < end)
121 |           addOverlay(cm, line.slice(start, end), re, state.options.style);
122 |         return;
123 |       }
124 |       var from = cm.getCursor("from"), to = cm.getCursor("to");
125 |       if (from.line != to.line) return;
126 |       if (state.options.wordsOnly && !isWord(cm, from, to)) return;
127 |       var selection = cm.getRange(from, to)
128 |       if (state.options.trim) selection = selection.replace(/^\s+|\s+$/g, "")
129 |       if (selection.length >= state.options.minChars)
130 |         addOverlay(cm, selection, false, state.options.style);
131 |     });
132 |   }
133 | 
134 |   function isWord(cm, from, to) {
135 |     var str = cm.getRange(from, to);
136 |     if (str.match(/^\w+$/) !== null) {
137 |         if (from.ch > 0) {
138 |             var pos = {line: from.line, ch: from.ch - 1};
139 |             var chr = cm.getRange(pos, from);
140 |             if (chr.match(/\W/) === null) return false;
141 |         }
142 |         if (to.ch < cm.getLine(from.line).length) {
143 |             var pos = {line: to.line, ch: to.ch + 1};
144 |             var chr = cm.getRange(to, pos);
145 |             if (chr.match(/\W/) === null) return false;
146 |         }
147 |         return true;
148 |     } else return false;
149 |   }
150 | 
151 |   function boundariesAround(stream, re) {
152 |     return (!stream.start || !re.test(stream.string.charAt(stream.start - 1))) &&
153 |       (stream.pos == stream.string.length || !re.test(stream.string.charAt(stream.pos)));
154 |   }
155 | 
156 |   function makeOverlay(query, hasBoundary, style) {
157 |     return {token: function(stream) {
158 |       if (stream.match(query) &&
159 |           (!hasBoundary || boundariesAround(stream, hasBoundary)))
160 |         return style;
161 |       stream.next();
162 |       stream.skipTo(query.charAt(0)) || stream.skipToEnd();
163 |     }};
164 |   }
165 | });
166 | 


--------------------------------------------------------------------------------
/hadui/web/vendor/cm/addon/search/matchesonscrollbar.css:
--------------------------------------------------------------------------------
1 | .CodeMirror-search-match {
2 |   background: gold;
3 |   border-top: 1px solid orange;
4 |   border-bottom: 1px solid orange;
5 |   -moz-box-sizing: border-box;
6 |   box-sizing: border-box;
7 |   opacity: .5;
8 | }
9 | 


--------------------------------------------------------------------------------
/hadui/web/vendor/cm/addon/search/matchesonscrollbar.js:
--------------------------------------------------------------------------------
 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
 2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
 3 | 
 4 | (function(mod) {
 5 |   if (typeof exports == "object" && typeof module == "object") // CommonJS
 6 |     mod(require("../../lib/codemirror"), require("./searchcursor"), require("../scroll/annotatescrollbar"));
 7 |   else if (typeof define == "function" && define.amd) // AMD
 8 |     define(["../../lib/codemirror", "./searchcursor", "../scroll/annotatescrollbar"], mod);
 9 |   else // Plain browser env
10 |     mod(CodeMirror);
11 | })(function(CodeMirror) {
12 |   "use strict";
13 | 
14 |   CodeMirror.defineExtension("showMatchesOnScrollbar", function(query, caseFold, options) {
15 |     if (typeof options == "string") options = {className: options};
16 |     if (!options) options = {};
17 |     return new SearchAnnotation(this, query, caseFold, options);
18 |   });
19 | 
20 |   function SearchAnnotation(cm, query, caseFold, options) {
21 |     this.cm = cm;
22 |     this.options = options;
23 |     var annotateOptions = {listenForChanges: false};
24 |     for (var prop in options) annotateOptions[prop] = options[prop];
25 |     if (!annotateOptions.className) annotateOptions.className = "CodeMirror-search-match";
26 |     this.annotation = cm.annotateScrollbar(annotateOptions);
27 |     this.query = query;
28 |     this.caseFold = caseFold;
29 |     this.gap = {from: cm.firstLine(), to: cm.lastLine() + 1};
30 |     this.matches = [];
31 |     this.update = null;
32 | 
33 |     this.findMatches();
34 |     this.annotation.update(this.matches);
35 | 
36 |     var self = this;
37 |     cm.on("change", this.changeHandler = function(_cm, change) { self.onChange(change); });
38 |   }
39 | 
40 |   var MAX_MATCHES = 1000;
41 | 
42 |   SearchAnnotation.prototype.findMatches = function() {
43 |     if (!this.gap) return;
44 |     for (var i = 0; i < this.matches.length; i++) {
45 |       var match = this.matches[i];
46 |       if (match.from.line >= this.gap.to) break;
47 |       if (match.to.line >= this.gap.from) this.matches.splice(i--, 1);
48 |     }
49 |     var cursor = this.cm.getSearchCursor(this.query, CodeMirror.Pos(this.gap.from, 0), {caseFold: this.caseFold, multiline: this.options.multiline});
50 |     var maxMatches = this.options && this.options.maxMatches || MAX_MATCHES;
51 |     while (cursor.findNext()) {
52 |       var match = {from: cursor.from(), to: cursor.to()};
53 |       if (match.from.line >= this.gap.to) break;
54 |       this.matches.splice(i++, 0, match);
55 |       if (this.matches.length > maxMatches) break;
56 |     }
57 |     this.gap = null;
58 |   };
59 | 
60 |   function offsetLine(line, changeStart, sizeChange) {
61 |     if (line <= changeStart) return line;
62 |     return Math.max(changeStart, line + sizeChange);
63 |   }
64 | 
65 |   SearchAnnotation.prototype.onChange = function(change) {
66 |     var startLine = change.from.line;
67 |     var endLine = CodeMirror.changeEnd(change).line;
68 |     var sizeChange = endLine - change.to.line;
69 |     if (this.gap) {
70 |       this.gap.from = Math.min(offsetLine(this.gap.from, startLine, sizeChange), change.from.line);
71 |       this.gap.to = Math.max(offsetLine(this.gap.to, startLine, sizeChange), change.from.line);
72 |     } else {
73 |       this.gap = {from: change.from.line, to: endLine + 1};
74 |     }
75 | 
76 |     if (sizeChange) for (var i = 0; i < this.matches.length; i++) {
77 |       var match = this.matches[i];
78 |       var newFrom = offsetLine(match.from.line, startLine, sizeChange);
79 |       if (newFrom != match.from.line) match.from = CodeMirror.Pos(newFrom, match.from.ch);
80 |       var newTo = offsetLine(match.to.line, startLine, sizeChange);
81 |       if (newTo != match.to.line) match.to = CodeMirror.Pos(newTo, match.to.ch);
82 |     }
83 |     clearTimeout(this.update);
84 |     var self = this;
85 |     this.update = setTimeout(function() { self.updateAfterChange(); }, 250);
86 |   };
87 | 
88 |   SearchAnnotation.prototype.updateAfterChange = function() {
89 |     this.findMatches();
90 |     this.annotation.update(this.matches);
91 |   };
92 | 
93 |   SearchAnnotation.prototype.clear = function() {
94 |     this.cm.off("change", this.changeHandler);
95 |     this.annotation.clear();
96 |   };
97 | });
98 | 


--------------------------------------------------------------------------------
/hadui/web/vendor/cm/addon/search/search.js:
--------------------------------------------------------------------------------
  1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
  2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
  3 | 
  4 | // Define search commands. Depends on dialog.js or another
  5 | // implementation of the openDialog method.
  6 | 
  7 | // Replace works a little oddly -- it will do the replace on the next
  8 | // Ctrl-G (or whatever is bound to findNext) press. You prevent a
  9 | // replace by making sure the match is no longer selected when hitting
 10 | // Ctrl-G.
 11 | 
 12 | (function(mod) {
 13 |   if (typeof exports == "object" && typeof module == "object") // CommonJS
 14 |     mod(require("../../lib/codemirror"), require("./searchcursor"), require("../dialog/dialog"));
 15 |   else if (typeof define == "function" && define.amd) // AMD
 16 |     define(["../../lib/codemirror", "./searchcursor", "../dialog/dialog"], mod);
 17 |   else // Plain browser env
 18 |     mod(CodeMirror);
 19 | })(function(CodeMirror) {
 20 |   "use strict";
 21 | 
 22 |   function searchOverlay(query, caseInsensitive) {
 23 |     if (typeof query == "string")
 24 |       query = new RegExp(query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), caseInsensitive ? "gi" : "g");
 25 |     else if (!query.global)
 26 |       query = new RegExp(query.source, query.ignoreCase ? "gi" : "g");
 27 | 
 28 |     return {token: function(stream) {
 29 |       query.lastIndex = stream.pos;
 30 |       var match = query.exec(stream.string);
 31 |       if (match && match.index == stream.pos) {
 32 |         stream.pos += match[0].length || 1;
 33 |         return "searching";
 34 |       } else if (match) {
 35 |         stream.pos = match.index;
 36 |       } else {
 37 |         stream.skipToEnd();
 38 |       }
 39 |     }};
 40 |   }
 41 | 
 42 |   function SearchState() {
 43 |     this.posFrom = this.posTo = this.lastQuery = this.query = null;
 44 |     this.overlay = null;
 45 |   }
 46 | 
 47 |   function getSearchState(cm) {
 48 |     return cm.state.search || (cm.state.search = new SearchState());
 49 |   }
 50 | 
 51 |   function queryCaseInsensitive(query) {
 52 |     return typeof query == "string" && query == query.toLowerCase();
 53 |   }
 54 | 
 55 |   function getSearchCursor(cm, query, pos) {
 56 |     // Heuristic: if the query string is all lowercase, do a case insensitive search.
 57 |     return cm.getSearchCursor(query, pos, {caseFold: queryCaseInsensitive(query), multiline: true});
 58 |   }
 59 | 
 60 |   function persistentDialog(cm, text, deflt, onEnter, onKeyDown) {
 61 |     cm.openDialog(text, onEnter, {
 62 |       value: deflt,
 63 |       selectValueOnOpen: true,
 64 |       closeOnEnter: false,
 65 |       onClose: function() { clearSearch(cm); },
 66 |       onKeyDown: onKeyDown
 67 |     });
 68 |   }
 69 | 
 70 |   function dialog(cm, text, shortText, deflt, f) {
 71 |     if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true});
 72 |     else f(prompt(shortText, deflt));
 73 |   }
 74 | 
 75 |   function confirmDialog(cm, text, shortText, fs) {
 76 |     if (cm.openConfirm) cm.openConfirm(text, fs);
 77 |     else if (confirm(shortText)) fs[0]();
 78 |   }
 79 | 
 80 |   function parseString(string) {
 81 |     return string.replace(/\\([nrt\\])/g, function(match, ch) {
 82 |       if (ch == "n") return "\n"
 83 |       if (ch == "r") return "\r"
 84 |       if (ch == "t") return "\t"
 85 |       if (ch == "\\") return "\\"
 86 |       return match
 87 |     })
 88 |   }
 89 | 
 90 |   function parseQuery(query) {
 91 |     var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
 92 |     if (isRE) {
 93 |       try { query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); }
 94 |       catch(e) {} // Not a regular expression after all, do a string search
 95 |     } else {
 96 |       query = parseString(query)
 97 |     }
 98 |     if (typeof query == "string" ? query == "" : query.test(""))
 99 |       query = /x^/;
100 |     return query;
101 |   }
102 | 
103 |   function startSearch(cm, state, query) {
104 |     state.queryText = query;
105 |     state.query = parseQuery(query);
106 |     cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query));
107 |     state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query));
108 |     cm.addOverlay(state.overlay);
109 |     if (cm.showMatchesOnScrollbar) {
110 |       if (state.annotate) { state.annotate.clear(); state.annotate = null; }
111 |       state.annotate = cm.showMatchesOnScrollbar(state.query, queryCaseInsensitive(state.query));
112 |     }
113 |   }
114 | 
115 |   function doSearch(cm, rev, persistent, immediate) {
116 |     var state = getSearchState(cm);
117 |     if (state.query) return findNext(cm, rev);
118 |     var q = cm.getSelection() || state.lastQuery;
119 |     if (q instanceof RegExp && q.source == "x^") q = null
120 |     if (persistent && cm.openDialog) {
121 |       var hiding = null
122 |       var searchNext = function(query, event) {
123 |         CodeMirror.e_stop(event);
124 |         if (!query) return;
125 |         if (query != state.queryText) {
126 |           startSearch(cm, state, query);
127 |           state.posFrom = state.posTo = cm.getCursor();
128 |         }
129 |         if (hiding) hiding.style.opacity = 1
130 |         findNext(cm, event.shiftKey, function(_, to) {
131 |           var dialog
132 |           if (to.line < 3 && document.querySelector &&
133 |               (dialog = cm.display.wrapper.querySelector(".CodeMirror-dialog")) &&
134 |               dialog.getBoundingClientRect().bottom - 4 > cm.cursorCoords(to, "window").top)
135 |             (hiding = dialog).style.opacity = .4
136 |         })
137 |       };
138 |       persistentDialog(cm, getQueryDialog(cm), q, searchNext, function(event, query) {
139 |         var keyName = CodeMirror.keyName(event)
140 |         var extra = cm.getOption('extraKeys'), cmd = (extra && extra[keyName]) || CodeMirror.keyMap[cm.getOption("keyMap")][keyName]
141 |         if (cmd == "findNext" || cmd == "findPrev" ||
142 |           cmd == "findPersistentNext" || cmd == "findPersistentPrev") {
143 |           CodeMirror.e_stop(event);
144 |           startSearch(cm, getSearchState(cm), query);
145 |           cm.execCommand(cmd);
146 |         } else if (cmd == "find" || cmd == "findPersistent") {
147 |           CodeMirror.e_stop(event);
148 |           searchNext(query, event);
149 |         }
150 |       });
151 |       if (immediate && q) {
152 |         startSearch(cm, state, q);
153 |         findNext(cm, rev);
154 |       }
155 |     } else {
156 |       dialog(cm, getQueryDialog(cm), "Search for:", q, function(query) {
157 |         if (query && !state.query) cm.operation(function() {
158 |           startSearch(cm, state, query);
159 |           state.posFrom = state.posTo = cm.getCursor();
160 |           findNext(cm, rev);
161 |         });
162 |       });
163 |     }
164 |   }
165 | 
166 |   function findNext(cm, rev, callback) {cm.operation(function() {
167 |     var state = getSearchState(cm);
168 |     var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo);
169 |     if (!cursor.find(rev)) {
170 |       cursor = getSearchCursor(cm, state.query, rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0));
171 |       if (!cursor.find(rev)) return;
172 |     }
173 |     cm.setSelection(cursor.from(), cursor.to());
174 |     cm.scrollIntoView({from: cursor.from(), to: cursor.to()}, 20);
175 |     state.posFrom = cursor.from(); state.posTo = cursor.to();
176 |     if (callback) callback(cursor.from(), cursor.to())
177 |   });}
178 | 
179 |   function clearSearch(cm) {cm.operation(function() {
180 |     var state = getSearchState(cm);
181 |     state.lastQuery = state.query;
182 |     if (!state.query) return;
183 |     state.query = state.queryText = null;
184 |     cm.removeOverlay(state.overlay);
185 |     if (state.annotate) { state.annotate.clear(); state.annotate = null; }
186 |   });}
187 | 
188 | 
189 |   function getQueryDialog(cm)  {
190 |     return '' + cm.phrase("Search:") + '  ' + cm.phrase("(Use /re/ syntax for regexp search)") + '';
191 |   }
192 |   function getReplaceQueryDialog(cm) {
193 |     return '  ' + cm.phrase("(Use /re/ syntax for regexp search)") + '';
194 |   }
195 |   function getReplacementQueryDialog(cm) {
196 |     return '' + cm.phrase("With:") + ' ';
197 |   }
198 |   function getDoReplaceConfirm(cm) {
199 |     return '' + cm.phrase("Replace?") + '     ';
200 |   }
201 | 
202 |   function replaceAll(cm, query, text) {
203 |     cm.operation(function() {
204 |       for (var cursor = getSearchCursor(cm, query); cursor.findNext();) {
205 |         if (typeof query != "string") {
206 |           var match = cm.getRange(cursor.from(), cursor.to()).match(query);
207 |           cursor.replace(text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
208 |         } else cursor.replace(text);
209 |       }
210 |     });
211 |   }
212 | 
213 |   function replace(cm, all) {
214 |     if (cm.getOption("readOnly")) return;
215 |     var query = cm.getSelection() || getSearchState(cm).lastQuery;
216 |     var dialogText = '' + (all ? cm.phrase("Replace all:") : cm.phrase("Replace:")) + '';
217 |     dialog(cm, dialogText + getReplaceQueryDialog(cm), dialogText, query, function(query) {
218 |       if (!query) return;
219 |       query = parseQuery(query);
220 |       dialog(cm, getReplacementQueryDialog(cm), cm.phrase("Replace with:"), "", function(text) {
221 |         text = parseString(text)
222 |         if (all) {
223 |           replaceAll(cm, query, text)
224 |         } else {
225 |           clearSearch(cm);
226 |           var cursor = getSearchCursor(cm, query, cm.getCursor("from"));
227 |           var advance = function() {
228 |             var start = cursor.from(), match;
229 |             if (!(match = cursor.findNext())) {
230 |               cursor = getSearchCursor(cm, query);
231 |               if (!(match = cursor.findNext()) ||
232 |                   (start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return;
233 |             }
234 |             cm.setSelection(cursor.from(), cursor.to());
235 |             cm.scrollIntoView({from: cursor.from(), to: cursor.to()});
236 |             confirmDialog(cm, getDoReplaceConfirm(cm), cm.phrase("Replace?"),
237 |                           [function() {doReplace(match);}, advance,
238 |                            function() {replaceAll(cm, query, text)}]);
239 |           };
240 |           var doReplace = function(match) {
241 |             cursor.replace(typeof query == "string" ? text :
242 |                            text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
243 |             advance();
244 |           };
245 |           advance();
246 |         }
247 |       });
248 |     });
249 |   }
250 | 
251 |   CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);};
252 |   CodeMirror.commands.findPersistent = function(cm) {clearSearch(cm); doSearch(cm, false, true);};
253 |   CodeMirror.commands.findPersistentNext = function(cm) {doSearch(cm, false, true, true);};
254 |   CodeMirror.commands.findPersistentPrev = function(cm) {doSearch(cm, true, true, true);};
255 |   CodeMirror.commands.findNext = doSearch;
256 |   CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);};
257 |   CodeMirror.commands.clearSearch = clearSearch;
258 |   CodeMirror.commands.replace = replace;
259 |   CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);};
260 | });
261 | 


--------------------------------------------------------------------------------
/hadui/web/vendor/cm/addon/wrap/hardwrap.js:
--------------------------------------------------------------------------------
  1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
  2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
  3 | 
  4 | (function(mod) {
  5 |   if (typeof exports == "object" && typeof module == "object") // CommonJS
  6 |     mod(require("../../lib/codemirror"));
  7 |   else if (typeof define == "function" && define.amd) // AMD
  8 |     define(["../../lib/codemirror"], mod);
  9 |   else // Plain browser env
 10 |     mod(CodeMirror);
 11 | })(function(CodeMirror) {
 12 |   "use strict";
 13 | 
 14 |   var Pos = CodeMirror.Pos;
 15 | 
 16 |   function findParagraph(cm, pos, options) {
 17 |     var startRE = options.paragraphStart || cm.getHelper(pos, "paragraphStart");
 18 |     for (var start = pos.line, first = cm.firstLine(); start > first; --start) {
 19 |       var line = cm.getLine(start);
 20 |       if (startRE && startRE.test(line)) break;
 21 |       if (!/\S/.test(line)) { ++start; break; }
 22 |     }
 23 |     var endRE = options.paragraphEnd || cm.getHelper(pos, "paragraphEnd");
 24 |     for (var end = pos.line + 1, last = cm.lastLine(); end <= last; ++end) {
 25 |       var line = cm.getLine(end);
 26 |       if (endRE && endRE.test(line)) { ++end; break; }
 27 |       if (!/\S/.test(line)) break;
 28 |     }
 29 |     return {from: start, to: end};
 30 |   }
 31 | 
 32 |   function findBreakPoint(text, column, wrapOn, killTrailingSpace) {
 33 |     var at = column
 34 |     while (at < text.length && text.charAt(at) == " ") at++
 35 |     for (; at > 0; --at)
 36 |       if (wrapOn.test(text.slice(at - 1, at + 1))) break;
 37 |     for (var first = true;; first = false) {
 38 |       var endOfText = at;
 39 |       if (killTrailingSpace)
 40 |         while (text.charAt(endOfText - 1) == " ") --endOfText;
 41 |       if (endOfText == 0 && first) at = column;
 42 |       else return {from: endOfText, to: at};
 43 |     }
 44 |   }
 45 | 
 46 |   function wrapRange(cm, from, to, options) {
 47 |     from = cm.clipPos(from); to = cm.clipPos(to);
 48 |     var column = options.column || 80;
 49 |     var wrapOn = options.wrapOn || /\s\S|-[^\.\d]/;
 50 |     var killTrailing = options.killTrailingSpace !== false;
 51 |     var changes = [], curLine = "", curNo = from.line;
 52 |     var lines = cm.getRange(from, to, false);
 53 |     if (!lines.length) return null;
 54 |     var leadingSpace = lines[0].match(/^[ \t]*/)[0];
 55 |     if (leadingSpace.length >= column) column = leadingSpace.length + 1
 56 | 
 57 |     for (var i = 0; i < lines.length; ++i) {
 58 |       var text = lines[i], oldLen = curLine.length, spaceInserted = 0;
 59 |       if (curLine && text && !wrapOn.test(curLine.charAt(curLine.length - 1) + text.charAt(0))) {
 60 |         curLine += " ";
 61 |         spaceInserted = 1;
 62 |       }
 63 |       var spaceTrimmed = "";
 64 |       if (i) {
 65 |         spaceTrimmed = text.match(/^\s*/)[0];
 66 |         text = text.slice(spaceTrimmed.length);
 67 |       }
 68 |       curLine += text;
 69 |       if (i) {
 70 |         var firstBreak = curLine.length > column && leadingSpace == spaceTrimmed &&
 71 |           findBreakPoint(curLine, column, wrapOn, killTrailing);
 72 |         // If this isn't broken, or is broken at a different point, remove old break
 73 |         if (!firstBreak || firstBreak.from != oldLen || firstBreak.to != oldLen + spaceInserted) {
 74 |           changes.push({text: [spaceInserted ? " " : ""],
 75 |                         from: Pos(curNo, oldLen),
 76 |                         to: Pos(curNo + 1, spaceTrimmed.length)});
 77 |         } else {
 78 |           curLine = leadingSpace + text;
 79 |           ++curNo;
 80 |         }
 81 |       }
 82 |       while (curLine.length > column) {
 83 |         var bp = findBreakPoint(curLine, column, wrapOn, killTrailing);
 84 |         changes.push({text: ["", leadingSpace],
 85 |                       from: Pos(curNo, bp.from),
 86 |                       to: Pos(curNo, bp.to)});
 87 |         curLine = leadingSpace + curLine.slice(bp.to);
 88 |         ++curNo;
 89 |       }
 90 |     }
 91 |     if (changes.length) cm.operation(function() {
 92 |       for (var i = 0; i < changes.length; ++i) {
 93 |         var change = changes[i];
 94 |         if (change.text || CodeMirror.cmpPos(change.from, change.to))
 95 |           cm.replaceRange(change.text, change.from, change.to);
 96 |       }
 97 |     });
 98 |     return changes.length ? {from: changes[0].from, to: CodeMirror.changeEnd(changes[changes.length - 1])} : null;
 99 |   }
100 | 
101 |   CodeMirror.defineExtension("wrapParagraph", function(pos, options) {
102 |     options = options || {};
103 |     if (!pos) pos = this.getCursor();
104 |     var para = findParagraph(this, pos, options);
105 |     return wrapRange(this, Pos(para.from, 0), Pos(para.to - 1), options);
106 |   });
107 | 
108 |   CodeMirror.commands.wrapLines = function(cm) {
109 |     cm.operation(function() {
110 |       var ranges = cm.listSelections(), at = cm.lastLine() + 1;
111 |       for (var i = ranges.length - 1; i >= 0; i--) {
112 |         var range = ranges[i], span;
113 |         if (range.empty()) {
114 |           var para = findParagraph(cm, range.head, {});
115 |           span = {from: Pos(para.from, 0), to: Pos(para.to - 1)};
116 |         } else {
117 |           span = {from: range.from(), to: range.to()};
118 |         }
119 |         if (span.to.line >= at) continue;
120 |         at = span.from.line;
121 |         wrapRange(cm, span.from, span.to, {});
122 |       }
123 |     });
124 |   };
125 | 
126 |   CodeMirror.defineExtension("wrapRange", function(from, to, options) {
127 |     return wrapRange(this, from, to, options || {});
128 |   });
129 | 
130 |   CodeMirror.defineExtension("wrapParagraphsInRange", function(from, to, options) {
131 |     options = options || {};
132 |     var cm = this, paras = [];
133 |     for (var line = from.line; line <= to.line;) {
134 |       var para = findParagraph(cm, Pos(line, 0), options);
135 |       paras.push(para);
136 |       line = para.to;
137 |     }
138 |     var madeChange = false;
139 |     if (paras.length) cm.operation(function() {
140 |       for (var i = paras.length - 1; i >= 0; --i)
141 |         madeChange = madeChange || wrapRange(cm, Pos(paras[i].from, 0), Pos(paras[i].to - 1), options);
142 |     });
143 |     return madeChange;
144 |   });
145 | });
146 | 


--------------------------------------------------------------------------------
/hadui/web/vendor/cm/lib/codemirror.css:
--------------------------------------------------------------------------------
  1 | /* BASICS */
  2 | 
  3 | .CodeMirror {
  4 |   /* Set height, width, borders, and global font properties here */
  5 |   font-family: monospace;
  6 |   height: 300px;
  7 |   color: black;
  8 |   direction: ltr;
  9 | }
 10 | 
 11 | /* PADDING */
 12 | 
 13 | .CodeMirror-lines {
 14 |   padding: 4px 0; /* Vertical padding around content */
 15 | }
 16 | .CodeMirror pre.CodeMirror-line,
 17 | .CodeMirror pre.CodeMirror-line-like {
 18 |   padding: 0 4px; /* Horizontal padding of content */
 19 | }
 20 | 
 21 | .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
 22 |   background-color: white; /* The little square between H and V scrollbars */
 23 | }
 24 | 
 25 | /* GUTTER */
 26 | 
 27 | .CodeMirror-gutters {
 28 |   border-right: 1px solid #ddd;
 29 |   background-color: #f7f7f7;
 30 |   white-space: nowrap;
 31 | }
 32 | .CodeMirror-linenumbers {}
 33 | .CodeMirror-linenumber {
 34 |   padding: 0 3px 0 5px;
 35 |   min-width: 20px;
 36 |   text-align: right;
 37 |   color: #999;
 38 |   white-space: nowrap;
 39 | }
 40 | 
 41 | .CodeMirror-guttermarker { color: black; }
 42 | .CodeMirror-guttermarker-subtle { color: #999; }
 43 | 
 44 | /* CURSOR */
 45 | 
 46 | .CodeMirror-cursor {
 47 |   border-left: 1px solid black;
 48 |   border-right: none;
 49 |   width: 0;
 50 | }
 51 | /* Shown when moving in bi-directional text */
 52 | .CodeMirror div.CodeMirror-secondarycursor {
 53 |   border-left: 1px solid silver;
 54 | }
 55 | .cm-fat-cursor .CodeMirror-cursor {
 56 |   width: auto;
 57 |   border: 0 !important;
 58 |   background: #7e7;
 59 | }
 60 | .cm-fat-cursor div.CodeMirror-cursors {
 61 |   z-index: 1;
 62 | }
 63 | .cm-fat-cursor-mark {
 64 |   background-color: rgba(20, 255, 20, 0.5);
 65 |   -webkit-animation: blink 1.06s steps(1) infinite;
 66 |   -moz-animation: blink 1.06s steps(1) infinite;
 67 |   animation: blink 1.06s steps(1) infinite;
 68 | }
 69 | .cm-animate-fat-cursor {
 70 |   width: auto;
 71 |   border: 0;
 72 |   -webkit-animation: blink 1.06s steps(1) infinite;
 73 |   -moz-animation: blink 1.06s steps(1) infinite;
 74 |   animation: blink 1.06s steps(1) infinite;
 75 |   background-color: #7e7;
 76 | }
 77 | @-moz-keyframes blink {
 78 |   0% {}
 79 |   50% { background-color: transparent; }
 80 |   100% {}
 81 | }
 82 | @-webkit-keyframes blink {
 83 |   0% {}
 84 |   50% { background-color: transparent; }
 85 |   100% {}
 86 | }
 87 | @keyframes blink {
 88 |   0% {}
 89 |   50% { background-color: transparent; }
 90 |   100% {}
 91 | }
 92 | 
 93 | /* Can style cursor different in overwrite (non-insert) mode */
 94 | .CodeMirror-overwrite .CodeMirror-cursor {}
 95 | 
 96 | .cm-tab { display: inline-block; text-decoration: inherit; }
 97 | 
 98 | .CodeMirror-rulers {
 99 |   position: absolute;
100 |   left: 0; right: 0; top: -50px; bottom: 0;
101 |   overflow: hidden;
102 | }
103 | .CodeMirror-ruler {
104 |   border-left: 1px solid #ccc;
105 |   top: 0; bottom: 0;
106 |   position: absolute;
107 | }
108 | 
109 | /* DEFAULT THEME */
110 | 
111 | .cm-s-default .cm-header {color: blue;}
112 | .cm-s-default .cm-quote {color: #090;}
113 | .cm-negative {color: #d44;}
114 | .cm-positive {color: #292;}
115 | .cm-header, .cm-strong {font-weight: bold;}
116 | .cm-em {font-style: italic;}
117 | .cm-link {text-decoration: underline;}
118 | .cm-strikethrough {text-decoration: line-through;}
119 | 
120 | .cm-s-default .cm-keyword {color: #708;}
121 | .cm-s-default .cm-atom {color: #219;}
122 | .cm-s-default .cm-number {color: #164;}
123 | .cm-s-default .cm-def {color: #00f;}
124 | .cm-s-default .cm-variable,
125 | .cm-s-default .cm-punctuation,
126 | .cm-s-default .cm-property,
127 | .cm-s-default .cm-operator {}
128 | .cm-s-default .cm-variable-2 {color: #05a;}
129 | .cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;}
130 | .cm-s-default .cm-comment {color: #a50;}
131 | .cm-s-default .cm-string {color: #a11;}
132 | .cm-s-default .cm-string-2 {color: #f50;}
133 | .cm-s-default .cm-meta {color: #555;}
134 | .cm-s-default .cm-qualifier {color: #555;}
135 | .cm-s-default .cm-builtin {color: #30a;}
136 | .cm-s-default .cm-bracket {color: #997;}
137 | .cm-s-default .cm-tag {color: #170;}
138 | .cm-s-default .cm-attribute {color: #00c;}
139 | .cm-s-default .cm-hr {color: #999;}
140 | .cm-s-default .cm-link {color: #00c;}
141 | 
142 | .cm-s-default .cm-error {color: #f00;}
143 | .cm-invalidchar {color: #f00;}
144 | 
145 | .CodeMirror-composing { border-bottom: 2px solid; }
146 | 
147 | /* Default styles for common addons */
148 | 
149 | div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;}
150 | div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
151 | .CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
152 | .CodeMirror-activeline-background {background: #e8f2ff;}
153 | 
154 | /* STOP */
155 | 
156 | /* The rest of this file contains styles related to the mechanics of
157 |    the editor. You probably shouldn't touch them. */
158 | 
159 | .CodeMirror {
160 |   position: relative;
161 |   overflow: hidden;
162 |   background: white;
163 | }
164 | 
165 | .CodeMirror-scroll {
166 |   overflow: scroll !important; /* Things will break if this is overridden */
167 |   /* 30px is the magic margin used to hide the element's real scrollbars */
168 |   /* See overflow: hidden in .CodeMirror */
169 |   margin-bottom: -30px; margin-right: -30px;
170 |   padding-bottom: 30px;
171 |   height: 100%;
172 |   outline: none; /* Prevent dragging from highlighting the element */
173 |   position: relative;
174 | }
175 | .CodeMirror-sizer {
176 |   position: relative;
177 |   border-right: 30px solid transparent;
178 | }
179 | 
180 | /* The fake, visible scrollbars. Used to force redraw during scrolling
181 |    before actual scrolling happens, thus preventing shaking and
182 |    flickering artifacts. */
183 | .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
184 |   position: absolute;
185 |   z-index: 6;
186 |   display: none;
187 | }
188 | .CodeMirror-vscrollbar {
189 |   right: 0; top: 0;
190 |   overflow-x: hidden;
191 |   overflow-y: scroll;
192 | }
193 | .CodeMirror-hscrollbar {
194 |   bottom: 0; left: 0;
195 |   overflow-y: hidden;
196 |   overflow-x: scroll;
197 | }
198 | .CodeMirror-scrollbar-filler {
199 |   right: 0; bottom: 0;
200 | }
201 | .CodeMirror-gutter-filler {
202 |   left: 0; bottom: 0;
203 | }
204 | 
205 | .CodeMirror-gutters {
206 |   position: absolute; left: 0; top: 0;
207 |   min-height: 100%;
208 |   z-index: 3;
209 | }
210 | .CodeMirror-gutter {
211 |   white-space: normal;
212 |   height: 100%;
213 |   display: inline-block;
214 |   vertical-align: top;
215 |   margin-bottom: -30px;
216 | }
217 | .CodeMirror-gutter-wrapper {
218 |   position: absolute;
219 |   z-index: 4;
220 |   background: none !important;
221 |   border: none !important;
222 | }
223 | .CodeMirror-gutter-background {
224 |   position: absolute;
225 |   top: 0; bottom: 0;
226 |   z-index: 4;
227 | }
228 | .CodeMirror-gutter-elt {
229 |   position: absolute;
230 |   cursor: default;
231 |   z-index: 4;
232 | }
233 | .CodeMirror-gutter-wrapper ::selection { background-color: transparent }
234 | .CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent }
235 | 
236 | .CodeMirror-lines {
237 |   cursor: text;
238 |   min-height: 1px; /* prevents collapsing before first draw */
239 | }
240 | .CodeMirror pre.CodeMirror-line,
241 | .CodeMirror pre.CodeMirror-line-like {
242 |   /* Reset some styles that the rest of the page might have set */
243 |   -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
244 |   border-width: 0;
245 |   background: transparent;
246 |   font-family: inherit;
247 |   font-size: inherit;
248 |   margin: 0;
249 |   white-space: pre;
250 |   word-wrap: normal;
251 |   line-height: inherit;
252 |   color: inherit;
253 |   z-index: 2;
254 |   position: relative;
255 |   overflow: visible;
256 |   -webkit-tap-highlight-color: transparent;
257 |   -webkit-font-variant-ligatures: contextual;
258 |   font-variant-ligatures: contextual;
259 | }
260 | .CodeMirror-wrap pre.CodeMirror-line,
261 | .CodeMirror-wrap pre.CodeMirror-line-like {
262 |   word-wrap: break-word;
263 |   white-space: pre-wrap;
264 |   word-break: normal;
265 | }
266 | 
267 | .CodeMirror-linebackground {
268 |   position: absolute;
269 |   left: 0; right: 0; top: 0; bottom: 0;
270 |   z-index: 0;
271 | }
272 | 
273 | .CodeMirror-linewidget {
274 |   position: relative;
275 |   z-index: 2;
276 |   padding: 0.1px; /* Force widget margins to stay inside of the container */
277 | }
278 | 
279 | .CodeMirror-widget {}
280 | 
281 | .CodeMirror-rtl pre { direction: rtl; }
282 | 
283 | .CodeMirror-code {
284 |   outline: none;
285 | }
286 | 
287 | /* Force content-box sizing for the elements where we expect it */
288 | .CodeMirror-scroll,
289 | .CodeMirror-sizer,
290 | .CodeMirror-gutter,
291 | .CodeMirror-gutters,
292 | .CodeMirror-linenumber {
293 |   -moz-box-sizing: content-box;
294 |   box-sizing: content-box;
295 | }
296 | 
297 | .CodeMirror-measure {
298 |   position: absolute;
299 |   width: 100%;
300 |   height: 0;
301 |   overflow: hidden;
302 |   visibility: hidden;
303 | }
304 | 
305 | .CodeMirror-cursor {
306 |   position: absolute;
307 |   pointer-events: none;
308 | }
309 | .CodeMirror-measure pre { position: static; }
310 | 
311 | div.CodeMirror-cursors {
312 |   visibility: hidden;
313 |   position: relative;
314 |   z-index: 3;
315 | }
316 | div.CodeMirror-dragcursors {
317 |   visibility: visible;
318 | }
319 | 
320 | .CodeMirror-focused div.CodeMirror-cursors {
321 |   visibility: visible;
322 | }
323 | 
324 | .CodeMirror-selected { background: #d9d9d9; }
325 | .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
326 | .CodeMirror-crosshair { cursor: crosshair; }
327 | .CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
328 | .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
329 | 
330 | .cm-searching {
331 |   background-color: #ffa;
332 |   background-color: rgba(255, 255, 0, .4);
333 | }
334 | 
335 | /* Used to force a border model for a node */
336 | .cm-force-border { padding-right: .1px; }
337 | 
338 | @media print {
339 |   /* Hide the cursor when printing */
340 |   .CodeMirror div.CodeMirror-cursors {
341 |     visibility: hidden;
342 |   }
343 | }
344 | 
345 | /* See issue #2901 */
346 | .cm-tab-wrap-hack:after { content: ''; }
347 | 
348 | /* Help users use markselection to safely style text background */
349 | span.CodeMirror-selectedtext { background: none; }
350 | 


--------------------------------------------------------------------------------
/hadui/web/vendor/cm/mode/haskell.js:
--------------------------------------------------------------------------------
  1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
  2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
  3 | 
  4 | (function(mod) {
  5 |   if (typeof exports == "object" && typeof module == "object") // CommonJS
  6 |     mod(require("../../lib/codemirror"));
  7 |   else if (typeof define == "function" && define.amd) // AMD
  8 |     define(["../../lib/codemirror"], mod);
  9 |   else // Plain browser env
 10 |     mod(CodeMirror);
 11 | })(function(CodeMirror) {
 12 | "use strict";
 13 | 
 14 | CodeMirror.defineMode("haskell", function(_config, modeConfig) {
 15 | 
 16 |   function switchState(source, setState, f) {
 17 |     setState(f);
 18 |     return f(source, setState);
 19 |   }
 20 | 
 21 |   // These should all be Unicode extended, as per the Haskell 2010 report
 22 |   var smallRE = /[a-z_]/;
 23 |   var largeRE = /[A-Z]/;
 24 |   var digitRE = /\d/;
 25 |   var hexitRE = /[0-9A-Fa-f]/;
 26 |   var octitRE = /[0-7]/;
 27 |   var idRE = /[a-z_A-Z0-9'\xa1-\uffff]/;
 28 |   var symbolRE = /[-!#$%&*+.\/<=>?@\\^|~:]/;
 29 |   var specialRE = /[(),;[\]`{}]/;
 30 |   var whiteCharRE = /[ \t\v\f]/; // newlines are handled in tokenizer
 31 | 
 32 |   function normal(source, setState) {
 33 |     if (source.eatWhile(whiteCharRE)) {
 34 |       return null;
 35 |     }
 36 | 
 37 |     var ch = source.next();
 38 |     if (specialRE.test(ch)) {
 39 |       if (ch == '{' && source.eat('-')) {
 40 |         var t = "comment";
 41 |         if (source.eat('#')) {
 42 |           t = "meta";
 43 |         }
 44 |         return switchState(source, setState, ncomment(t, 1));
 45 |       }
 46 |       return null;
 47 |     }
 48 | 
 49 |     if (ch == '\'') {
 50 |       if (source.eat('\\')) {
 51 |         source.next();  // should handle other escapes here
 52 |       }
 53 |       else {
 54 |         source.next();
 55 |       }
 56 |       if (source.eat('\'')) {
 57 |         return "string";
 58 |       }
 59 |       return "string error";
 60 |     }
 61 | 
 62 |     if (ch == '"') {
 63 |       return switchState(source, setState, stringLiteral);
 64 |     }
 65 | 
 66 |     if (largeRE.test(ch)) {
 67 |       source.eatWhile(idRE);
 68 |       if (source.eat('.')) {
 69 |         return "qualifier";
 70 |       }
 71 |       return "variable-2";
 72 |     }
 73 | 
 74 |     if (smallRE.test(ch)) {
 75 |       source.eatWhile(idRE);
 76 |       return "variable";
 77 |     }
 78 | 
 79 |     if (digitRE.test(ch)) {
 80 |       if (ch == '0') {
 81 |         if (source.eat(/[xX]/)) {
 82 |           source.eatWhile(hexitRE); // should require at least 1
 83 |           return "integer";
 84 |         }
 85 |         if (source.eat(/[oO]/)) {
 86 |           source.eatWhile(octitRE); // should require at least 1
 87 |           return "number";
 88 |         }
 89 |       }
 90 |       source.eatWhile(digitRE);
 91 |       var t = "number";
 92 |       if (source.match(/^\.\d+/)) {
 93 |         t = "number";
 94 |       }
 95 |       if (source.eat(/[eE]/)) {
 96 |         t = "number";
 97 |         source.eat(/[-+]/);
 98 |         source.eatWhile(digitRE); // should require at least 1
 99 |       }
100 |       return t;
101 |     }
102 | 
103 |     if (ch == "." && source.eat("."))
104 |       return "keyword";
105 | 
106 |     if (symbolRE.test(ch)) {
107 |       if (ch == '-' && source.eat(/-/)) {
108 |         source.eatWhile(/-/);
109 |         if (!source.eat(symbolRE)) {
110 |           source.skipToEnd();
111 |           return "comment";
112 |         }
113 |       }
114 |       var t = "variable";
115 |       if (ch == ':') {
116 |         t = "variable-2";
117 |       }
118 |       source.eatWhile(symbolRE);
119 |       return t;
120 |     }
121 | 
122 |     return "error";
123 |   }
124 | 
125 |   function ncomment(type, nest) {
126 |     if (nest == 0) {
127 |       return normal;
128 |     }
129 |     return function(source, setState) {
130 |       var currNest = nest;
131 |       while (!source.eol()) {
132 |         var ch = source.next();
133 |         if (ch == '{' && source.eat('-')) {
134 |           ++currNest;
135 |         }
136 |         else if (ch == '-' && source.eat('}')) {
137 |           --currNest;
138 |           if (currNest == 0) {
139 |             setState(normal);
140 |             return type;
141 |           }
142 |         }
143 |       }
144 |       setState(ncomment(type, currNest));
145 |       return type;
146 |     };
147 |   }
148 | 
149 |   function stringLiteral(source, setState) {
150 |     while (!source.eol()) {
151 |       var ch = source.next();
152 |       if (ch == '"') {
153 |         setState(normal);
154 |         return "string";
155 |       }
156 |       if (ch == '\\') {
157 |         if (source.eol() || source.eat(whiteCharRE)) {
158 |           setState(stringGap);
159 |           return "string";
160 |         }
161 |         if (source.eat('&')) {
162 |         }
163 |         else {
164 |           source.next(); // should handle other escapes here
165 |         }
166 |       }
167 |     }
168 |     setState(normal);
169 |     return "string error";
170 |   }
171 | 
172 |   function stringGap(source, setState) {
173 |     if (source.eat('\\')) {
174 |       return switchState(source, setState, stringLiteral);
175 |     }
176 |     source.next();
177 |     setState(normal);
178 |     return "error";
179 |   }
180 | 
181 | 
182 |   var wellKnownWords = (function() {
183 |     var wkw = {};
184 |     function setType(t) {
185 |       return function () {
186 |         for (var i = 0; i < arguments.length; i++)
187 |           wkw[arguments[i]] = t;
188 |       };
189 |     }
190 | 
191 |     setType("keyword")(
192 |       "case", "class", "data", "default", "deriving", "do", "else", "foreign",
193 |       "if", "import", "in", "infix", "infixl", "infixr", "instance", "let",
194 |       "module", "newtype", "of", "then", "type", "where", "_");
195 | 
196 |     setType("keyword")(
197 |       "\.\.", ":", "::", "=", "\\", "<-", "->", "@", "~", "=>");
198 | 
199 |     setType("builtin")(
200 |       "!!", "$!", "$", "&&", "+", "++", "-", ".", "/", "/=", "<", "<*", "<=",
201 |       "<$>", "<*>", "=<<", "==", ">", ">=", ">>", ">>=", "^", "^^", "||", "*",
202 |       "*>", "**");
203 | 
204 |     setType("builtin")(
205 |       "Applicative", "Bool", "Bounded", "Char", "Double", "EQ", "Either", "Enum",
206 |       "Eq", "False", "FilePath", "Float", "Floating", "Fractional", "Functor",
207 |       "GT", "IO", "IOError", "Int", "Integer", "Integral", "Just", "LT", "Left",
208 |       "Maybe", "Monad", "Nothing", "Num", "Ord", "Ordering", "Rational", "Read",
209 |       "ReadS", "Real", "RealFloat", "RealFrac", "Right", "Show", "ShowS",
210 |       "String", "True");
211 | 
212 |     setType("builtin")(
213 |       "abs", "acos", "acosh", "all", "and", "any", "appendFile", "asTypeOf",
214 |       "asin", "asinh", "atan", "atan2", "atanh", "break", "catch", "ceiling",
215 |       "compare", "concat", "concatMap", "const", "cos", "cosh", "curry",
216 |       "cycle", "decodeFloat", "div", "divMod", "drop", "dropWhile", "either",
217 |       "elem", "encodeFloat", "enumFrom", "enumFromThen", "enumFromThenTo",
218 |       "enumFromTo", "error", "even", "exp", "exponent", "fail", "filter",
219 |       "flip", "floatDigits", "floatRadix", "floatRange", "floor", "fmap",
220 |       "foldl", "foldl1", "foldr", "foldr1", "fromEnum", "fromInteger",
221 |       "fromIntegral", "fromRational", "fst", "gcd", "getChar", "getContents",
222 |       "getLine", "head", "id", "init", "interact", "ioError", "isDenormalized",
223 |       "isIEEE", "isInfinite", "isNaN", "isNegativeZero", "iterate", "last",
224 |       "lcm", "length", "lex", "lines", "log", "logBase", "lookup", "map",
225 |       "mapM", "mapM_", "max", "maxBound", "maximum", "maybe", "min", "minBound",
226 |       "minimum", "mod", "negate", "not", "notElem", "null", "odd", "or",
227 |       "otherwise", "pi", "pred", "print", "product", "properFraction", "pure",
228 |       "putChar", "putStr", "putStrLn", "quot", "quotRem", "read", "readFile",
229 |       "readIO", "readList", "readLn", "readParen", "reads", "readsPrec",
230 |       "realToFrac", "recip", "rem", "repeat", "replicate", "return", "reverse",
231 |       "round", "scaleFloat", "scanl", "scanl1", "scanr", "scanr1", "seq",
232 |       "sequence", "sequence_", "show", "showChar", "showList", "showParen",
233 |       "showString", "shows", "showsPrec", "significand", "signum", "sin",
234 |       "sinh", "snd", "span", "splitAt", "sqrt", "subtract", "succ", "sum",
235 |       "tail", "take", "takeWhile", "tan", "tanh", "toEnum", "toInteger",
236 |       "toRational", "truncate", "uncurry", "undefined", "unlines", "until",
237 |       "unwords", "unzip", "unzip3", "userError", "words", "writeFile", "zip",
238 |       "zip3", "zipWith", "zipWith3");
239 | 
240 |     var override = modeConfig.overrideKeywords;
241 |     if (override) for (var word in override) if (override.hasOwnProperty(word))
242 |       wkw[word] = override[word];
243 | 
244 |     return wkw;
245 |   })();
246 | 
247 | 
248 | 
249 |   return {
250 |     startState: function ()  { return { f: normal }; },
251 |     copyState:  function (s) { return { f: s.f }; },
252 | 
253 |     token: function(stream, state) {
254 |       var t = state.f(stream, function(s) { state.f = s; });
255 |       var w = stream.current();
256 |       return wellKnownWords.hasOwnProperty(w) ? wellKnownWords[w] : t;
257 |     },
258 | 
259 |     blockCommentStart: "{-",
260 |     blockCommentEnd: "-}",
261 |     lineComment: "--"
262 |   };
263 | 
264 | });
265 | 
266 | CodeMirror.defineMIME("text/x-haskell", "haskell");
267 | 
268 | });
269 | 


--------------------------------------------------------------------------------
/hadui/web/vendor/cm/theme/elegant.css:
--------------------------------------------------------------------------------
 1 | .cm-s-elegant span.cm-number, .cm-s-elegant span.cm-string, .cm-s-elegant span.cm-atom { color: #762; }
 2 | .cm-s-elegant span.cm-comment { color: #262; font-style: italic; line-height: 1em; }
 3 | .cm-s-elegant span.cm-meta { color: #555; font-style: italic; line-height: 1em; }
 4 | .cm-s-elegant span.cm-variable { color: black; }
 5 | .cm-s-elegant span.cm-variable-2 { color: #b11; }
 6 | .cm-s-elegant span.cm-qualifier { color: #555; }
 7 | .cm-s-elegant span.cm-keyword { color: #730; }
 8 | .cm-s-elegant span.cm-builtin { color: #30a; }
 9 | .cm-s-elegant span.cm-link { color: #762; }
10 | .cm-s-elegant span.cm-error { background-color: #fdd; }
11 | 
12 | .cm-s-elegant .CodeMirror-activeline-background { background: #e8f2ff; }
13 | .cm-s-elegant .CodeMirror-matchingbracket { outline:1px solid grey; color:black !important; }
14 | 


--------------------------------------------------------------------------------
/hadui/web/vendor/cm/theme/monokai.css:
--------------------------------------------------------------------------------
 1 | /* Based on Sublime Text's Monokai theme */
 2 | 
 3 | .cm-s-monokai.CodeMirror { background: #272822; color: #f8f8f2; }
 4 | .cm-s-monokai div.CodeMirror-selected { background: #49483E; }
 5 | .cm-s-monokai .CodeMirror-line::selection, .cm-s-monokai .CodeMirror-line > span::selection, .cm-s-monokai .CodeMirror-line > span > span::selection { background: rgba(73, 72, 62, .99); }
 6 | .cm-s-monokai .CodeMirror-line::-moz-selection, .cm-s-monokai .CodeMirror-line > span::-moz-selection, .cm-s-monokai .CodeMirror-line > span > span::-moz-selection { background: rgba(73, 72, 62, .99); }
 7 | .cm-s-monokai .CodeMirror-gutters { background: #272822; border-right: 0px; }
 8 | .cm-s-monokai .CodeMirror-guttermarker { color: white; }
 9 | .cm-s-monokai .CodeMirror-guttermarker-subtle { color: #d0d0d0; }
10 | .cm-s-monokai .CodeMirror-linenumber { color: #d0d0d0; }
11 | .cm-s-monokai .CodeMirror-cursor { border-left: 1px solid #f8f8f0; }
12 | 
13 | .cm-s-monokai span.cm-comment { color: #75715e; }
14 | .cm-s-monokai span.cm-atom { color: #ae81ff; }
15 | .cm-s-monokai span.cm-number { color: #ae81ff; }
16 | 
17 | .cm-s-monokai span.cm-comment.cm-attribute { color: #97b757; }
18 | .cm-s-monokai span.cm-comment.cm-def { color: #bc9262; }
19 | .cm-s-monokai span.cm-comment.cm-tag { color: #bc6283; }
20 | .cm-s-monokai span.cm-comment.cm-type { color: #5998a6; }
21 | 
22 | .cm-s-monokai span.cm-property, .cm-s-monokai span.cm-attribute { color: #a6e22e; }
23 | .cm-s-monokai span.cm-keyword { color: #f92672; }
24 | .cm-s-monokai span.cm-builtin { color: #66d9ef; }
25 | .cm-s-monokai span.cm-string { color: #e6db74; }
26 | 
27 | .cm-s-monokai span.cm-variable { color: #f8f8f2; }
28 | .cm-s-monokai span.cm-variable-2 { color: #9effff; }
29 | .cm-s-monokai span.cm-variable-3, .cm-s-monokai span.cm-type { color: #66d9ef; }
30 | .cm-s-monokai span.cm-def { color: #fd971f; }
31 | .cm-s-monokai span.cm-bracket { color: #f8f8f2; }
32 | .cm-s-monokai span.cm-tag { color: #f92672; }
33 | .cm-s-monokai span.cm-header { color: #ae81ff; }
34 | .cm-s-monokai span.cm-link { color: #ae81ff; }
35 | .cm-s-monokai span.cm-error { background: #f92672; color: #f8f8f0; }
36 | 
37 | .cm-s-monokai .CodeMirror-activeline-background { background: #373831; }
38 | .cm-s-monokai .CodeMirror-matchingbracket {
39 |   text-decoration: underline;
40 |   color: white !important;
41 | }
42 | 


--------------------------------------------------------------------------------
/hadui/web/vendor/mui/LICENSE.txt:
--------------------------------------------------------------------------------
 1 | The MIT License (MIT)
 2 | 
 3 | Copyright (c) 2015 Andres Morey
 4 | 
 5 | The following license applies to all parts of this software except as
 6 | documented below:
 7 | 
 8 | ====
 9 | 
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | 
17 | The above copyright notice and this permission notice shall be included in
18 | all copies or substantial portions of the Software.
19 | 
20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 | THE SOFTWARE.
27 | 
28 | ====
29 | 
30 | All files located in the node_modules and bower_components directories are
31 | externally maintained libraries used by this software which have their
32 | own licenses; we recommend you read them, as their terms may differ from
33 | the terms above.
34 | 


--------------------------------------------------------------------------------
/hadui/web/vendor/mui/README.md:
--------------------------------------------------------------------------------
1 | # Material Design CSS Framework
2 | 
3 | Please check out https://github.com/muicss/mui
4 | 


--------------------------------------------------------------------------------
/hadui/web/wsc.js:
--------------------------------------------------------------------------------
  1 | /**
  2 |  * WebSocket Connection
  3 |  *
  4 |  */
  5 | 
  6 | import { hasLogBox, uiLog, clearLog } from "/log.js";
  7 | 
  8 | export class WSC {
  9 |   constructor(url) {
 10 |     this.url = url;
 11 |     this.ws = null;
 12 |     this.bins = null;
 13 |     this.waiters = null;
 14 |   }
 15 | 
 16 |   async getUrl() {
 17 |     if (this.url) return this.url;
 18 |     let wsPort = await $.get("/:");
 19 |     return "ws://" + location.hostname + ":" + wsPort;
 20 |   }
 21 | 
 22 |   init(ws) {
 23 |     this.ws = ws;
 24 |     this.bins = [];
 25 |     this.waiters = [];
 26 |   }
 27 | 
 28 |   async handleError(err, errDetails) {
 29 |     console.error("Unexpected WS error: ", err, errDetails);
 30 |     debugger;
 31 |     if (hasLogBox()) uiLog(err, "err-msg", errDetails);
 32 |   }
 33 | 
 34 |   /**
 35 |    * return a promise resolving to a connected WebSocket object,
 36 |    * which can be used to send outgoing commands asynchronously.
 37 |    */
 38 |   dial() {
 39 |     return new Promise((resolve, reject) => {
 40 |       let ws = this.ws;
 41 |       let waiters = this.waiters;
 42 |       if (null !== ws) {
 43 |         if (WebSocket.OPEN === ws.readyState) {
 44 |           resolve(ws);
 45 |           return;
 46 |         }
 47 |         if (WebSocket.CONNECTING === ws.readyState) {
 48 |           if (null !== waiters) {
 49 |             waiters.push([resolve, reject]);
 50 |             return;
 51 |           } else {
 52 |             console.warn("?!");
 53 |             debugger;
 54 |           }
 55 |         }
 56 |         this.ws = null;
 57 |       }
 58 |       if (null !== waiters) {
 59 |         this.waiters = null;
 60 |         for (let [resolve, reject] of waiters) {
 61 |           reject("WS reconnecting");
 62 |         }
 63 |       }
 64 |       this.getUrl().then(
 65 |         url => {
 66 |           ws = new WebSocket(url);
 67 |           ws.binaryType = "arraybuffer";
 68 | 
 69 |           this.init(ws);
 70 |           let bins = this.bins;
 71 |           let waiters = this.waiters;
 72 |           waiters.push([resolve, reject]);
 73 | 
 74 |           ws.onopen = () => {
 75 |             for (let [resolve, reject] of waiters) {
 76 |               resolve(ws);
 77 |             }
 78 |             if (this.waiters === waiters) {
 79 |               this.waiters = null;
 80 |             }
 81 |           };
 82 |           ws.onerror = ee => {
 83 |             console.error("WS error:", ee);
 84 |             // WS error event doesn't contain description, defer handling to close event
 85 |             // see: https://stackoverflow.com/a/18804298/6394508
 86 |           };
 87 |           ws.onclose = ce => {
 88 |             console.warn("WS closed.", ce);
 89 |             const msg =
 90 |               "WebSocket closed, code=" + ce.code + "  reason:" + ce.reason;
 91 |             if (1000 != ce.code) {
 92 |               this.handleError(msg);
 93 |             }
 94 |             for (let [resolve, reject] of waiters) {
 95 |               reject(new Error(msg));
 96 |             }
 97 |             if (this.waiters === waiters) {
 98 |               this.waiters = null;
 99 |             }
100 |           };
101 |           ws.onmessage = me => {
102 |             if (me.data instanceof ArrayBuffer) {
103 |               bins.push(me.data);
104 |               return;
105 |             }
106 |             if ("string" !== typeof me.data) {
107 |               debugger;
108 |               throw "WS msg of type " + typeof me.data + " ?!";
109 |             }
110 | 
111 |             let json_cmd;
112 |             try {
113 |               json_cmd = JSON.parse(me.data);
114 |             } catch (err) {
115 |               console.log("Error parsing ws msg:", me.data, err);
116 |               let closeWS = true; // can change this to false from debugger console
117 |               debugger;
118 |               if (closeWS) {
119 |                 ws.close();
120 |               }
121 |             }
122 |             if ("err" === json_cmd.type) {
123 |               console.error("WS error:", json_cmd);
124 |               let { errText, errDetails } = json_cmd;
125 |               debugger;
126 |               this.handleError(errText, errDetails);
127 |               bins.length = 0; // todo: this really desirable ?
128 |             } else if ("msg" === json_cmd.type) {
129 |               let { msgText, msgType, msgDetails } = json_cmd;
130 |               uiLog(msgText, msgType || "msg", msgDetails);
131 |             } else if ("clear" === json_cmd.type) {
132 |               clearLog();
133 |             } else if ("call" === json_cmd.type) {
134 |               // method call
135 |               let { name, args } = json_cmd;
136 |               try {
137 |                 let mth = this[name];
138 |                 if (!Array.isArray(args)) {
139 |                   args = [args];
140 |                 }
141 |                 mth.apply(this, args);
142 |               } catch (err) {
143 |                 console.error(
144 |                   "Error calling method " + name + " from WS:",
145 |                   err,
146 |                   json_cmd
147 |                 );
148 |                 let closeWS = true; // can change this to false from debugger console
149 |                 debugger;
150 |                 if (closeWS) {
151 |                   ws.close();
152 |                 }
153 |               }
154 |             } else {
155 |               console.error("WS msg not understood:", json_cmd);
156 |               let closeWS = true; // can change this to false from debugger console
157 |               debugger;
158 |               if (closeWS) {
159 |                 ws.close();
160 |               }
161 |             }
162 |           };
163 |         },
164 |         err => {
165 |           console.error("Error making WS connection:", err);
166 |           debugger;
167 |           this.handleError(err);
168 |           reject(err);
169 |         }
170 |       );
171 |     });
172 |   }
173 | 
174 |   openWindow(url, windowName) {
175 |     window.open(url, windowName);
176 |   }
177 | }
178 | 
179 | export default WSC;
180 | 


--------------------------------------------------------------------------------
/nixpkgs-overlays/ghc865ife-overlay.nix:
--------------------------------------------------------------------------------
 1 | # This is the Nix overlay to arm an experimental branch of GHC
 2 | # as the default compiler, together with a full Haskell package
 3 | # set (i.e. `haskellPackages`) with it.
 4 | #
 5 | # The compiler will be compiled from a source distribution, full
 6 | # source of the branch is at this repository:
 7 | #   https://gitlab.haskell.org/complyue/ghc/tree/ghc-8.6-ife
 8 | self: super:
 9 | let
10 | 
11 |   # the compiler
12 |   compiler865ife = super.haskell.compiler.ghc865.overrideAttrs (oldAttrs: {
13 |     # renaming the compiler will fail later compilations with it,
14 |     # as described at https://github.com/NixOS/nixpkgs/issues/73443
15 |     # so do NOT do it!
16 |     # name = "${oldAttrs.name}-ife";
17 | 
18 |     src = super.fetchurl {
19 |       url =
20 |         "https://gitlab.haskell.org/complyue/ghc-ife-sdist/raw/master/ghc-8.6.5-src.tar.xz";
21 |       sha256 = "0wf5v1ry3rlwhbsxlvka3qscdb4jz4jn7w3jckvwysh0fm1bavs5";
22 |     };
23 |   });
24 | 
25 |   # the package set
26 |   haskellPackages865ife = super.haskell.packages.ghc865.override {
27 |     ghc = compiler865ife;
28 |   };
29 | 
30 | in {
31 | 
32 |   # put the compiler & package set to standard location
33 |   haskell = super.haskell // {
34 |     compiler = super.haskell.compiler // { ghc865ife = compiler865ife; };
35 |     packages = super.haskell.packages // { ghc865ife = haskellPackages865ife; };
36 |   };
37 | 
38 |   # make this the default Haskell package set
39 |   haskellPackages = haskellPackages865ife;
40 |   # well the default can still be further overridden by other overlays
41 | 
42 | }
43 | 


--------------------------------------------------------------------------------
/shell.nix:
--------------------------------------------------------------------------------
1 | # this defines the Nix env for Hadui the package to be built
2 | with (import ./. { });
3 | haskellPackages.hadui.envFunc { withHoogle = true; }
4 | 


--------------------------------------------------------------------------------
/stack.yaml:
--------------------------------------------------------------------------------
1 | resolver: lts-14.27
2 | 
3 | packages:
4 |   - hadui
5 | 
6 | system-ghc: true
7 | nix:
8 |   enable: false
9 | 


--------------------------------------------------------------------------------