├── .envrc.old ├── .envrc.private.template.old ├── .ghci ├── .github └── workflows │ ├── build-linux-arm64.yml │ ├── build-linux-x86_64.yml │ ├── build-macos-arm64.yml │ ├── build-macos-x86_64.yml │ └── build-windows-x86_64.yml ├── .gitignore ├── .travis.yml ├── ContributorAgreement.pdf ├── LICENSE ├── README.md ├── apps ├── app │ ├── elm.json │ ├── interop │ │ ├── messages.ts │ │ ├── utils │ │ │ ├── json.ts │ │ │ └── log.ts │ │ └── watchtower │ │ │ └── question.ts │ └── src │ │ ├── Editor.elm │ │ ├── Elm │ │ ├── CallGraph.elm │ │ └── ProjectStatus.elm │ │ ├── Explainer.elm │ │ ├── Flags.elm │ │ ├── Main.elm │ │ ├── Model.elm │ │ ├── Navigator.elm │ │ ├── Ports.elm │ │ ├── Question.elm │ │ ├── Ui.elm │ │ ├── Ui │ │ ├── Card.elm │ │ ├── Type.elm │ │ └── WindowHeader.elm │ │ └── VSCode │ │ ├── Colors.elm │ │ └── SyntaxColors.elm ├── elm-dev │ ├── .gitignore │ ├── .vscode │ │ └── extensions.json │ ├── README.md │ ├── index.html │ ├── package.json │ ├── pnpm-lock.yaml │ ├── src-tauri │ │ ├── .gitignore │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── build.rs │ │ ├── capabilities │ │ │ └── migrated.json │ │ ├── gen │ │ │ └── schemas │ │ │ │ ├── acl-manifests.json │ │ │ │ ├── capabilities.json │ │ │ │ ├── desktop-schema.json │ │ │ │ └── macOS-schema.json │ │ ├── icons │ │ │ ├── 128x128.png │ │ │ ├── 128x128@2x.png │ │ │ ├── 32x32.png │ │ │ ├── Square107x107Logo.png │ │ │ ├── Square142x142Logo.png │ │ │ ├── Square150x150Logo.png │ │ │ ├── Square284x284Logo.png │ │ │ ├── Square30x30Logo.png │ │ │ ├── Square310x310Logo.png │ │ │ ├── Square44x44Logo.png │ │ │ ├── Square71x71Logo.png │ │ │ ├── Square89x89Logo.png │ │ │ ├── StoreLogo.png │ │ │ ├── icon.icns │ │ │ ├── icon.ico │ │ │ └── icon.png │ │ ├── src │ │ │ ├── lib.rs │ │ │ └── main.rs │ │ └── tauri.conf.json │ ├── src │ │ ├── assets │ │ │ ├── tauri.svg │ │ │ ├── typescript.svg │ │ │ └── vite.svg │ │ ├── main.ts │ │ └── styles.css │ ├── tsconfig.json │ └── vite.config.ts ├── elm-dev2 │ ├── .gitignore │ ├── .vscode │ │ └── extensions.json │ ├── README.md │ ├── elm-dev-vite │ │ ├── elm-error-json.js │ │ ├── hot-client.ts │ │ └── index.ts │ ├── elm.generate.json │ ├── elm.json │ ├── index.html │ ├── package.json │ ├── src-tauri │ │ ├── .gitignore │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── build.rs │ │ ├── capabilities │ │ │ └── default.json │ │ ├── icons │ │ │ ├── 128x128.png │ │ │ ├── 128x128@2x.png │ │ │ ├── 32x32.png │ │ │ ├── Square107x107Logo.png │ │ │ ├── Square142x142Logo.png │ │ │ ├── Square150x150Logo.png │ │ │ ├── Square284x284Logo.png │ │ │ ├── Square30x30Logo.png │ │ │ ├── Square310x310Logo.png │ │ │ ├── Square44x44Logo.png │ │ │ ├── Square71x71Logo.png │ │ │ ├── Square89x89Logo.png │ │ │ ├── StoreLogo.png │ │ │ ├── icon.icns │ │ │ ├── icon.ico │ │ │ └── icon.png │ │ ├── src │ │ │ ├── lib.rs │ │ │ └── main.rs │ │ └── tauri.conf.json │ ├── src │ │ ├── app │ │ │ ├── Broadcast.elm │ │ │ ├── Data │ │ │ │ ├── CallGraph.elm │ │ │ │ ├── Editor.elm │ │ │ │ ├── ProjectStatus.elm │ │ │ │ └── Question.elm │ │ │ ├── Docs │ │ │ │ ├── Ref.elm │ │ │ │ └── Ref │ │ │ │ │ └── Get.elm │ │ │ ├── Flags.elm │ │ │ ├── Listen │ │ │ │ └── DevServer.elm │ │ │ ├── Main.elm │ │ │ ├── Page │ │ │ │ ├── Guide.elm │ │ │ │ ├── Home.elm │ │ │ │ ├── Module.elm │ │ │ │ ├── Package.elm │ │ │ │ └── Reference.elm │ │ │ ├── Store │ │ │ │ ├── Guides.elm │ │ │ │ ├── Modules.elm │ │ │ │ ├── Packages.elm │ │ │ │ └── Projects.elm │ │ │ ├── Ui.elm │ │ │ └── Ui │ │ │ │ ├── Attr.elm │ │ │ │ ├── Docs │ │ │ │ └── Block.elm │ │ │ │ ├── Interactive.elm │ │ │ │ ├── Interactive │ │ │ │ └── Controls.elm │ │ │ │ ├── Markdown.elm │ │ │ │ ├── Module.elm │ │ │ │ ├── Nav.elm │ │ │ │ ├── Syntax.elm │ │ │ │ └── Type.elm │ │ ├── assets │ │ │ ├── tauri.svg │ │ │ ├── typescript.svg │ │ │ └── vite.svg │ │ ├── js │ │ │ ├── effect │ │ │ │ ├── clipboard.ts │ │ │ │ ├── local-storage.ts │ │ │ │ ├── scroll.ts │ │ │ │ └── text-selection.ts │ │ │ ├── effects.ts │ │ │ ├── util │ │ │ │ └── json.ts │ │ │ └── webcomponents │ │ │ │ ├── elm-portal.ts │ │ │ │ ├── index.ts │ │ │ │ └── interactive.ts │ │ ├── main.ts │ │ └── styles.css │ ├── tsconfig.json │ └── vite.config.ts └── vscode │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── elm.configuration.json │ ├── media │ ├── icons │ │ └── chevron-right.svg │ └── panel.js │ ├── package.json │ ├── pnpm-lock.yaml │ ├── scripts │ └── copy_deps.sh │ ├── src │ ├── elmFormat.ts │ ├── extension.ts │ ├── interactive.ts │ ├── interactive │ │ └── elm.json │ ├── node-elm-compiler.d.ts │ ├── panel │ │ ├── README.md │ │ ├── messages.ts │ │ └── panel.ts │ ├── utils │ │ ├── editorCoords.ts │ │ ├── elmUtils.ts │ │ ├── icons.ts │ │ ├── json.ts │ │ ├── log.ts │ │ ├── script.ts │ │ └── vscodeColorPalette.ts │ ├── watchtower.ts │ └── watchtower │ │ ├── codelensProvider.ts │ │ ├── diagnostics.ts │ │ └── question.ts │ ├── syntaxes │ ├── codeblock.json │ └── elm.json │ ├── testProject │ ├── elm.json │ ├── example-errors │ │ └── typecheck.json │ ├── output │ │ ├── docs-files.json │ │ ├── docs-modules.json │ │ ├── docs-package.json │ │ ├── entrypoints.json │ │ ├── explain.json │ │ ├── imports.json │ │ ├── usage-type.json │ │ ├── usage.json │ │ └── warnings.json │ └── src │ │ ├── Alias.elm │ │ ├── AlternativeMain.elm │ │ ├── Imported.elm │ │ ├── Main.elm │ │ ├── OtherPorts.elm │ │ └── Ui │ │ └── Arbor.elm │ ├── tsconfig.json │ ├── tslint.json │ └── vsc-extension-quickstart.md ├── builder └── src │ ├── BackgroundWriter.hs │ ├── Build.hs │ ├── Deps │ ├── Bump.hs │ ├── Diff.hs │ ├── Registry.hs │ ├── Solver.hs │ └── Website.hs │ ├── Elm │ ├── Details.hs │ └── Outline.hs │ ├── File.hs │ ├── Generate.hs │ ├── Http.hs │ ├── Reporting.hs │ ├── Reporting │ ├── Exit.hs │ ├── Exit │ │ └── Help.hs │ └── Task.hs │ └── Stuff.hs ├── cabal.config ├── cabal.project ├── cabal.project.freeze ├── compiler └── src │ ├── AST │ ├── Canonical.hs │ ├── Optimized.hs │ ├── Source.hs │ └── Utils │ │ ├── Binop.hs │ │ ├── Shader.hs │ │ └── Type.hs │ ├── Canonicalize │ ├── Effects.hs │ ├── Environment.hs │ ├── Environment │ │ ├── Dups.hs │ │ ├── Foreign.hs │ │ └── Local.hs │ ├── Expression.hs │ ├── Module.hs │ ├── Pattern.hs │ └── Type.hs │ ├── Compile.hs │ ├── Data │ ├── Bag.hs │ ├── Index.hs │ ├── Map │ │ └── Utils.hs │ ├── Name.hs │ ├── NonEmptyList.hs │ ├── OneOrMore.hs │ └── Utf8.hs │ ├── Elm │ ├── Compiler │ │ ├── Imports.hs │ │ ├── Type.hs │ │ └── Type │ │ │ └── Extract.hs │ ├── Constraint.hs │ ├── Docs.hs │ ├── Float.hs │ ├── Interface.hs │ ├── Kernel.hs │ ├── Licenses.hs │ ├── Magnitude.hs │ ├── ModuleName.hs │ ├── Package.hs │ ├── String.hs │ └── Version.hs │ ├── Generate │ ├── Html.hs │ ├── JavaScript.hs │ ├── JavaScript │ │ ├── Builder.hs │ │ ├── Expression.hs │ │ ├── Functions.hs │ │ └── Name.hs │ └── Mode.hs │ ├── Json │ ├── Decode.hs │ ├── Encode.hs │ └── String.hs │ ├── Nitpick │ ├── Debug.hs │ └── PatternMatches.hs │ ├── Optimize │ ├── Case.hs │ ├── DecisionTree.hs │ ├── Expression.hs │ ├── Module.hs │ ├── Names.hs │ └── Port.hs │ ├── Parse │ ├── Declaration.hs │ ├── Expression.hs │ ├── Keyword.hs │ ├── Module.hs │ ├── Number.hs │ ├── Pattern.hs │ ├── Primitives.hs │ ├── Shader.hs │ ├── Space.hs │ ├── String.hs │ ├── Symbol.hs │ ├── Type.hs │ └── Variable.hs │ ├── Reporting │ ├── Annotation.hs │ ├── Doc.hs │ ├── Error.hs │ ├── Error │ │ ├── Canonicalize.hs │ │ ├── Docs.hs │ │ ├── Import.hs │ │ ├── Json.hs │ │ ├── Main.hs │ │ ├── Pattern.hs │ │ ├── Syntax.hs │ │ └── Type.hs │ ├── Render │ │ ├── Code.hs │ │ ├── Type.hs │ │ └── Type │ │ │ └── Localizer.hs │ ├── Report.hs │ ├── Result.hs │ ├── Suggest.hs │ └── Warning.hs │ └── Type │ ├── Constrain │ ├── Expression.hs │ ├── Module.hs │ └── Pattern.hs │ ├── Error.hs │ ├── Instantiate.hs │ ├── Occurs.hs │ ├── Solve.hs │ ├── Type.hs │ ├── Unify.hs │ └── UnionFind.hs ├── distribution ├── .gitignore ├── build-linux-arm64-musl.sh ├── build-linux-x86_64-musl.sh ├── build-macos-arm64.sh ├── build-macos-x86_64.sh ├── common.sh ├── docker │ └── x86_64-musl.dockerfile └── readme.md ├── docs ├── elm.json │ ├── application.md │ └── package.md └── upgrade-instructions │ ├── 0.16.md │ ├── 0.17.md │ ├── 0.18.md │ ├── 0.19.0.md │ ├── 0.19.1.md │ └── earlier.md ├── elm-dev.cabal ├── example ├── elm.json └── src │ └── Test │ ├── Basic.elm │ └── Module.elm ├── ext-common ├── Ext │ ├── Common.hs │ ├── CompileHelpers │ │ ├── Disk.hs │ │ ├── Generic.hs │ │ └── Memory.hs │ ├── CompileMode.hs │ ├── CompileProxy.hs │ ├── Disk │ │ └── Build.hs │ ├── ElmFormat.hs │ ├── FileCache.hs │ ├── FileProxy.hs │ ├── Log.hs │ ├── MemoryCached │ │ ├── BackgroundWriter.hs │ │ ├── Build.hs │ │ ├── Details.hs │ │ ├── Generate.hs │ │ ├── readme.md │ │ └── vendor.sh │ ├── Project │ │ └── Find.hs │ └── Sanity.hs └── readme.md ├── ext-dev ├── CommandParser.hs ├── DEVELOPING.md ├── ElmDevElmVersion.hs ├── Ext │ ├── Dev.hs │ └── Dev │ │ ├── CallGraph.hs │ │ ├── Canonicalize.hs │ │ ├── Docs.hs │ │ ├── EntryPoints.hs │ │ ├── Explain.hs │ │ ├── Find.hs │ │ ├── Find │ │ ├── Canonical.hs │ │ └── Source.hs │ │ ├── Help.hs │ │ ├── Imports.hs │ │ ├── InScope.hs │ │ ├── Json │ │ └── Encode.hs │ │ ├── Lookup.hs │ │ ├── Package.hs │ │ ├── Project.hs │ │ ├── Project │ │ └── Ports.hs │ │ ├── Search.hs │ │ ├── Usage.hs │ │ └── Warnings.hs ├── Llamadera.hs ├── MainDev.hs ├── StandaloneInstances.hs ├── Terminal │ ├── Colors.hs │ └── Dev │ │ ├── Args.hs │ │ ├── Error.hs │ │ └── Out.hs ├── Test.hs ├── Util.hs └── readme.md ├── ext-generate ├── DEVELOPING.md ├── Gen │ ├── Commands.hs │ ├── Commands │ │ ├── Init.hs │ │ └── Make.hs │ ├── Config.hs │ ├── Generate.hs │ ├── Javascript.hs │ ├── RunConfig.hs │ ├── Templates.hs │ └── Templates │ │ └── Loader.hs ├── Modify.hs ├── Modify │ └── Ui.hs ├── README.md └── generator │ ├── .gitignore │ ├── README.md │ ├── app │ └── templates │ │ ├── customizable │ │ ├── App │ │ │ ├── Page │ │ │ │ └── Error.elm │ │ │ └── View.elm │ │ ├── Broadcast.elm │ │ ├── Effect.elm │ │ ├── Effect │ │ │ ├── Clipboard.elm │ │ │ ├── Debounce.elm │ │ │ ├── File.elm │ │ │ ├── Focus.elm │ │ │ ├── Http.elm │ │ │ ├── LocalStorage.elm │ │ │ ├── Nav.elm │ │ │ ├── Page.elm │ │ │ ├── Random.elm │ │ │ └── Scroll.elm │ │ ├── Listen.elm │ │ ├── Listen │ │ │ └── LocalStorage.elm │ │ ├── Main.elm │ │ └── WebComponent │ │ │ └── Portal.elm │ │ ├── oneOff │ │ ├── Auth.elm │ │ ├── Effect.elm │ │ ├── Listen.elm │ │ ├── Page.elm │ │ ├── Store.elm │ │ └── effect.ts │ │ ├── toHidden │ │ └── App │ │ │ ├── Page.elm │ │ │ ├── State.elm │ │ │ └── Store.elm │ │ ├── toJs │ │ ├── js │ │ │ ├── effect │ │ │ │ ├── clipboard.ts │ │ │ │ ├── local-storage.ts │ │ │ │ ├── scroll.ts │ │ │ │ └── text-selection.ts │ │ │ ├── effects.ts │ │ │ └── webcomponents │ │ │ │ ├── elm-portal.ts │ │ │ │ └── index.ts │ │ └── main.ts │ │ └── toRoot │ │ ├── .gitignore │ │ ├── index.html │ │ ├── tsconfig.json │ │ ├── vite.config.js │ │ └── viteElm.ts │ ├── assets │ └── templates │ │ └── toHidden │ │ └── Asset │ │ └── FrontMatter.elm │ ├── build.sh │ ├── codegen │ └── elm.codegen.json │ ├── dev │ ├── Example │ │ ├── Build.elm │ │ ├── CallStack.elm │ │ ├── Interactive.elm │ │ ├── Interactive │ │ │ ├── Build.elm │ │ │ └── Rendered.elm │ │ └── Type.elm │ ├── Exemplar.elm │ ├── Generate.elm │ ├── Generate │ │ └── PageId.elm │ ├── Interactive.elm │ ├── Options.elm │ ├── README.md │ ├── elm.codegen.json │ ├── elm.json │ └── engine │ │ └── Ui │ │ └── Theme │ │ └── Input.elm │ ├── elm.json │ ├── graphql │ └── templates │ │ └── oneOff │ │ └── Effect.elm │ ├── index.ts │ ├── main │ ├── Extra │ │ └── Parser.elm │ ├── Generate │ │ ├── Assets.elm │ │ ├── Docs.elm │ │ ├── Docs │ │ │ └── Module.elm │ │ └── Route.elm │ ├── Options │ │ ├── App.elm │ │ ├── Assets.elm │ │ └── Docs.elm │ ├── Path.elm │ ├── Press │ │ ├── Generate.elm │ │ ├── Generate │ │ │ ├── Engine.elm │ │ │ └── Regions.elm │ │ └── Model.elm │ └── Run.elm │ ├── package.json │ ├── tests │ └── Test │ │ ├── Frontmatter.elm │ │ └── Route.elm │ ├── theme │ ├── Theme.elm │ ├── Theme │ │ ├── Color.elm │ │ ├── Decoder.elm │ │ ├── Generate.elm │ │ └── Generate │ │ │ ├── Stylesheet.elm │ │ │ └── Ui.elm │ ├── elm.json │ └── templates │ │ ├── customizable │ │ └── Ui │ │ │ ├── Button.elm │ │ │ ├── Divider.elm │ │ │ ├── Dropdown.elm │ │ │ ├── Editor.elm │ │ │ ├── Input │ │ │ ├── Switch.elm │ │ │ └── Text.elm │ │ │ ├── Markdown.elm │ │ │ ├── Modal.elm │ │ │ ├── Table │ │ │ └── Column.elm │ │ │ └── Tooltip.elm │ │ └── toJs │ │ └── tiptap.ts │ └── tsconfig.json ├── ext-sentry ├── Ext │ ├── Filewatch.hs │ └── Sentry.hs └── readme.md ├── ext-watchtower ├── README.md └── Watchtower │ ├── Editor.hs │ ├── Live.hs │ ├── Live │ ├── Client.hs │ └── Compile.hs │ ├── MCP.hs │ ├── Questions.hs │ ├── Server.hs │ ├── State │ ├── Compile.hs │ ├── Discover.hs │ └── Project.hs │ ├── StaticAssets.hs │ ├── Test.hs │ ├── Version.hs │ └── Websocket.hs ├── hints ├── bad-recursion.md ├── comparing-custom-types.md ├── comparing-records.md ├── implicit-casts.md ├── import-cycles.md ├── imports.md ├── infinite-type.md ├── init.md ├── missing-patterns.md ├── optimize.md ├── port-modules.md ├── recursive-alias.md ├── repl.md ├── shadowing.md ├── tuples.md └── type-annotations.md ├── installers-elm-dev └── npm │ ├── .gitignore │ ├── .npmignore │ ├── README.md │ ├── bin │ └── elm-dev │ ├── binary.js │ ├── install.js │ ├── internal-docs │ ├── PUBLISHING.md │ └── README.md │ ├── package.json │ ├── packages │ ├── darwin_arm64 │ │ ├── README.md │ │ └── package.json │ ├── darwin_x64 │ │ ├── README.md │ │ └── package.json │ ├── linux_arm64 │ │ ├── README.md │ │ └── package.json │ ├── linux_x64 │ │ ├── README.md │ │ └── package.json │ └── win32_x64 │ │ ├── README.md │ │ └── package.json │ ├── scripts │ └── download-binaries.sh │ └── troubleshooting.md ├── installers ├── README.md ├── linux │ ├── Dockerfile │ └── README.md ├── mac │ ├── Distribution.xml │ ├── README.md │ ├── Resources │ │ └── en.lproj │ │ │ ├── conclusion.rtf │ │ │ └── welcome.rtf │ ├── helper-scripts │ │ ├── elm-startup.sh │ │ └── uninstall.sh │ ├── make-installer.sh │ ├── postinstall │ └── preinstall ├── npm │ ├── .gitignore │ ├── .npmignore │ ├── PUBLISHING.md │ ├── README.md │ ├── bin │ │ └── elm │ ├── download.js │ ├── install.js │ ├── package.json │ └── troubleshooting.md └── win │ ├── CreateInternetShortcut.nsh │ ├── Nsisfile.nsi │ ├── README.md │ ├── inst.dat │ ├── logo.ico │ ├── make_installer.cmd │ ├── removefrompath.vbs │ ├── uninst.dat │ ├── updatepath.vbs │ └── welcome.bmp ├── package.json ├── reactor ├── assets │ ├── favicon.ico │ ├── source-code-pro.ttf │ ├── source-sans-pro.ttf │ └── styles.css ├── check.py ├── elm.json └── src │ ├── Deps.elm │ ├── Errors.elm │ ├── Index.elm │ ├── Index │ ├── Icon.elm │ ├── Navigator.elm │ └── Skeleton.elm │ ├── NotFound.elm │ └── mock.txt ├── roadmap.md ├── scripts ├── test-generation.sh └── test-project.sh ├── shell.nix ├── stack.yaml ├── stack.yaml.lock ├── terminal ├── impl │ ├── Terminal.hs │ └── Terminal │ │ ├── Chomp.hs │ │ ├── Error.hs │ │ ├── Helpers.hs │ │ └── Internal.hs └── src │ ├── Bump.hs │ ├── Develop.hs │ ├── Develop │ ├── Generate │ │ ├── Help.hs │ │ └── Index.hs │ ├── Socket.hs │ ├── StaticFiles.hs │ └── StaticFiles │ │ └── Build.hs │ ├── Diff.hs │ ├── Init.hs │ ├── Install.hs │ ├── Main.hs │ ├── Make.hs │ ├── Publish.hs │ └── Repl.hs └── worker ├── elm.cabal ├── elm.json ├── nginx.conf ├── outlines ├── compile │ └── elm.json └── repl │ └── elm.json └── src ├── Artifacts.hs ├── Cors.hs ├── Endpoint ├── Compile.hs ├── Donate.hs └── Repl.hs ├── Errors.elm └── Main.hs /.envrc.old: -------------------------------------------------------------------------------- 1 | 2 | #!/usr/bin/env bash 3 | # We're using direnv: https://direnv.net/ 4 | # docs are here: https://direnv.net/man/direnv-stdlib.1.html 5 | 6 | # Check out .envrc.private.template to get started 7 | # Use it to start your own .envrc.private, which isn't tracked by version control 8 | 9 | source_env_if_exists .envrc.private -------------------------------------------------------------------------------- /.envrc.private.template.old: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ## Copy this file to `.envrc.private` 4 | ## Then running `direnv allow` in the terminal will load your environment 5 | ## whenever you're in this directory 6 | 7 | export ELM_WATCHTOWER_START_PROJECT=$(CHANGEME) -------------------------------------------------------------------------------- /.ghci: -------------------------------------------------------------------------------- 1 | :set -fbyte-code 2 | :set -fobject-code 3 | :def restart const $ return $ unlines [":r","Watchtower.Test.serve"] 4 | :set prompt "\ESC[34mλ: \ESC[m" 5 | :set -XOverloadedStrings -------------------------------------------------------------------------------- /.github/workflows/build-linux-arm64.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - distribute 5 | - linux 6 | - linux-arm64 7 | 8 | name: Build Linux arm64 9 | jobs: 10 | build: 11 | name: Build Linux arm64 12 | # For some reason this OOM's on community m1 but not on local m1, so we use a dedicated linux-arm64 box for now 13 | runs-on: lamdera-community-linux-arm64 14 | steps: 15 | - name: Install SSH key 16 | uses: shimataro/ssh-key-action@v2 17 | with: 18 | key: ${{ secrets.GH_USER_SCP_KEY }} 19 | name: id_ed25519 20 | known_hosts: ${{ secrets.KNOWN_HOSTS }} 21 | if_key_exists: replace 22 | - uses: actions/checkout@v3 23 | - run: echo "${HOME}/.local/bin" >> $GITHUB_PATH 24 | - name: Run distribution script 25 | run: | 26 | cd distribution 27 | ./build-linux-arm64-musl.sh 28 | -------------------------------------------------------------------------------- /.github/workflows/build-linux-x86_64.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - distribute 5 | - linux 6 | - linux-x86_64 7 | 8 | name: Build Linux x86_64 9 | jobs: 10 | build: 11 | name: Build Linux x86_64 12 | runs-on: lamdera-community-linux-x86_64 13 | steps: 14 | - name: Install SSH key 15 | uses: shimataro/ssh-key-action@v2 16 | with: 17 | key: ${{ secrets.GH_USER_SCP_KEY }} 18 | name: id_ed25519 19 | known_hosts: ${{ secrets.KNOWN_HOSTS }} 20 | if_key_exists: replace 21 | - uses: actions/checkout@v3 22 | - run: echo "${HOME}/.local/bin" >> $GITHUB_PATH 23 | - name: Run distribution script 24 | run: | 25 | cd distribution 26 | ./build-linux-x86_64-musl.sh 27 | -------------------------------------------------------------------------------- /.github/workflows/build-macos-arm64.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - distribute 5 | - macos 6 | - macos-arm64 7 | 8 | name: Build MacOS arm64 9 | jobs: 10 | build: 11 | name: Build MacOS arm64 12 | runs-on: lamdera-community-m1 13 | steps: 14 | - name: Install SSH key 15 | uses: shimataro/ssh-key-action@v2 16 | with: 17 | key: ${{ secrets.GH_USER_SCP_KEY }} 18 | name: id_ed25519 19 | known_hosts: ${{ secrets.KNOWN_HOSTS }} 20 | if_key_exists: replace 21 | - uses: actions/checkout@v3 22 | - run: echo "${HOME}/.local/bin" >> $GITHUB_PATH 23 | - name: Run distribution script 24 | run: | 25 | test -x "$(which ghcup)" && curl https://downloads.haskell.org/~ghcup/aarch64-apple-darwin-ghcup -o ~/.local/bin/ghcup && chmod a+x ~/.local/bin/ghcup 26 | cd distribution 27 | ./build-macos-arm64.sh 28 | -------------------------------------------------------------------------------- /.github/workflows/build-macos-x86_64.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - distribute 5 | - macos 6 | - macos-x86_64 7 | 8 | name: Build MacOS x86_64 9 | jobs: 10 | build: 11 | name: Build MacOS x86_64 12 | runs-on: lamdera-community-m1 13 | steps: 14 | - name: Install SSH key 15 | uses: shimataro/ssh-key-action@v2 16 | with: 17 | key: ${{ secrets.GH_USER_SCP_KEY }} 18 | name: id_ed25519 19 | known_hosts: ${{ secrets.KNOWN_HOSTS }} 20 | if_key_exists: replace 21 | - uses: actions/checkout@v3 22 | - run: echo "${HOME}/.local/bin" >> $GITHUB_PATH 23 | - name: Run distribution script 24 | run: | 25 | test -x "$(which ghcup)" && curl https://downloads.haskell.org/~ghcup/aarch64-apple-darwin-ghcup -o ~/.local/bin/ghcup && chmod a+x ~/.local/bin/ghcup 26 | cd distribution 27 | ./build-macos-x86_64.sh 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | elm-stuff 2 | dist 3 | dist-newstyle 4 | cabal-dev 5 | .cabal-sandbox/ 6 | cabal.sandbox.config 7 | .DS_Store 8 | *~ 9 | travis.log 10 | 11 | 12 | .stack-work 13 | node_modules 14 | .envrc.private 15 | 16 | 17 | .vscode/settings.json 18 | playground 19 | bun.lock -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: minimal 2 | services: docker 3 | 4 | env: 5 | global: 6 | - LINUX_ARCHIVE=binary-for-linux-64-bit.gz 7 | 8 | before_install: 9 | - docker build -t elm -f installers/linux/Dockerfile . 10 | - docker cp $(docker create elm):/usr/local/bin/elm . 11 | - gzip -9 -c elm > $LINUX_ARCHIVE 12 | 13 | deploy: 14 | provider: releases 15 | api_key: 16 | secure: Yz2Lo4u9rZQ7Ee7ohAsrZpkqsYDUerCSMdSQIH8ryrf7phHhiloPEkTKsM+NupHqU/LEAVsunxbau4QrCEjA2vPavAPVk8cKomRUWK/YjbXHKa24hPkal2c+A2bnMQ6w3qYk/PjL9rW+Goq++/SNLcYZwHBV0Chl2blivMwWCSA= 17 | file: $LINUX_ARCHIVE 18 | skip_cleanup: true 19 | on: 20 | branch: master 21 | tags: true 22 | 23 | notifications: 24 | email: 25 | recipients: 26 | - rlefevre@dmy.fr 27 | on_success: change 28 | on_failure: change 29 | -------------------------------------------------------------------------------- /ContributorAgreement.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/ContributorAgreement.pdf -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2012-present Evan Czaplicki 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Elm Dev 2 | 3 | Elm Dev is a version of the Elm compiler that is made to support editing tools. 4 | 5 | Not to be confused with Elm itself which lives here: https://elm-lang.org/ 6 | 7 | This package is for toolmakers, so if you're just starting out using Elm, you likely don't need this tool directly. 8 | 9 | Install via `npm install -g elm-dev` if you want to play with it. It's currently experimental, but will likely be stable soon. 10 | 11 | Currently this is a command line tool with the following commands that print or output JSON. 12 | 13 | - `warnings` - List missing type signatures and unused values. 14 | - `entrypoints` - Detect what `.elm` files are the potential roots of a project. This will also report any ports relevant to a specific entrypoint as well as the type signatures of those ports. 15 | - `docs` - Generate `docs.json` for any package, or any local `.elm` file. 16 | - `imports` - Given a list of modules, report all files and packages that they collectively depends on. This is useful for 17 | - `usage` - Given a module, return all usages of that module in a given project. 18 | - `explain` - Given a fully qualified type name, provide it's full definition. 19 | 20 | Each command may instead report compilation errors if the file or project fails to compile. 21 | 22 | ## Roadmap 23 | 24 | The above functionality is a first pass on what would be useful for `elm-dev` to report and has been published to allow downstream projects to try stuff out. 25 | 26 | In the medium term, the intention is to support the language-server protocol and to adjust functionaltiy based on downstream projects. 27 | -------------------------------------------------------------------------------- /apps/app/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "src" 5 | ], 6 | "elm-version": "0.19.1", 7 | "dependencies": { 8 | "direct": { 9 | "elm/browser": "1.0.2", 10 | "elm/core": "1.0.2", 11 | "elm/html": "1.0.0", 12 | "elm/http": "2.0.0", 13 | "elm/json": "1.1.2", 14 | "elm/project-metadata-utils": "1.0.2", 15 | "elm/svg": "1.0.1", 16 | "elm/time": "1.0.0", 17 | "elm/url": "1.0.0", 18 | "gingko/time-distance": "2.3.1", 19 | "mdgriffith/elm-ui": "1.1.0" 20 | }, 21 | "indirect": { 22 | "elm/bytes": "1.0.8", 23 | "elm/file": "1.0.5", 24 | "elm/parser": "1.1.0", 25 | "elm/virtual-dom": "1.0.2" 26 | } 27 | }, 28 | "test-dependencies": { 29 | "direct": {}, 30 | "indirect": {} 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /apps/app/interop/utils/json.ts: -------------------------------------------------------------------------------- 1 | export const parse = (source: string) => { 2 | try { 3 | return JSON.parse(source); 4 | } catch (err) { 5 | console.log("Error parsing watchtower Msg:"); 6 | console.log(" " + err); 7 | console.log("Original Msg"); 8 | console.log(source); 9 | return null; 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /apps/app/interop/utils/log.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | 3 | const watchtower = vscode.window.createOutputChannel("Elm Watchtower"); 4 | 5 | export function log(str) { 6 | watchtower.appendLine(str); 7 | } 8 | 9 | 10 | export function obj(name, o) { 11 | watchtower.appendLine(name); 12 | for (const [key, value] of Object.entries(o)) { 13 | 14 | if (Array.isArray(value)) { 15 | let first = true 16 | watchtower.appendLine(" " + key + ":"); 17 | if (value.length == 0) { 18 | watchtower.appendLine(" []"); 19 | } else { 20 | for (const index in value) { 21 | const subval = value[index] 22 | if (first) { 23 | watchtower.appendLine(" [ " + subval); 24 | first = false 25 | } else { 26 | watchtower.appendLine(" , " + subval); 27 | } 28 | 29 | } 30 | watchtower.appendLine(" ]"); 31 | } 32 | } else if ( 33 | typeof value === 'object' && 34 | value !== null 35 | ) { 36 | watchtower.appendLine(" " + key + ": "); 37 | watchtower.appendLine(Object.keys(value).join("\n")); 38 | for (const [subKey, subValue] of Object.entries(value)) { 39 | watchtower.appendLine(" " + subKey + ": " + subValue); 40 | } 41 | 42 | } else { 43 | watchtower.appendLine(" " + key + ": " + value); 44 | } 45 | 46 | } 47 | } 48 | 49 | 50 | -------------------------------------------------------------------------------- /apps/app/src/Flags.elm: -------------------------------------------------------------------------------- 1 | module Flags exposing 2 | ( Flags 3 | , Platform(..) 4 | , decoder 5 | ) 6 | 7 | import Json.Decode as Decode 8 | 9 | 10 | type alias Flags = 11 | { platform : Platform 12 | } 13 | 14 | 15 | type Platform 16 | = Windows 17 | | Mac 18 | | Linux 19 | | VSCode 20 | 21 | 22 | decoder : Decode.Decoder Flags 23 | decoder = 24 | Decode.map Flags 25 | (Decode.field "platform" platformDecoder) 26 | 27 | 28 | {-| 29 | 30 | List is taken from here: https://tauri.app/v1/api/js/os 31 | 32 | 'linux', 'darwin', 'ios', 'freebsd', 'dragonfly', 'netbsd', 'openbsd', 'solaris', 'android', 'win32' 33 | 34 | But we also add in VSCode. 35 | 36 | -} 37 | platformDecoder : Decode.Decoder Platform 38 | platformDecoder = 39 | Decode.string 40 | |> Decode.andThen 41 | (\str -> 42 | case str of 43 | "win32" -> 44 | Decode.succeed Windows 45 | 46 | "darwin" -> 47 | Decode.succeed Mac 48 | 49 | "macos" -> 50 | Decode.succeed Mac 51 | 52 | "vscode" -> 53 | Decode.succeed VSCode 54 | 55 | _ -> 56 | Decode.succeed Linux 57 | ) 58 | -------------------------------------------------------------------------------- /apps/app/src/Model.elm: -------------------------------------------------------------------------------- 1 | module Model exposing 2 | ( Model 3 | , Msg(..) 4 | , Viewing(..) 5 | ) 6 | 7 | import Dict exposing (Dict) 8 | import Editor 9 | import Elm.CallGraph 10 | import Elm.ProjectStatus 11 | import Flags 12 | import Http 13 | import Json.Decode as Decode 14 | import Ports 15 | import Question 16 | import Set exposing (Set) 17 | import Time 18 | 19 | 20 | type alias Model = 21 | { server : Ports.Server 22 | , flags : Maybe Flags.Flags 23 | 24 | -- editor 25 | , active : Maybe Editor.Editor 26 | , visible : List Editor.Editor 27 | , projects : List Elm.ProjectStatus.Project 28 | , projectsVersion : Int 29 | 30 | -- local UI state 31 | , viewing : Viewing 32 | , now : Maybe Time.Posix 33 | , lastUpdated : Maybe Time.Posix 34 | 35 | -- per-file information 36 | , warnings : Dict FilePath (List Ports.Warning) 37 | , errorMenuVisible : Bool 38 | , errorCodeExpanded : Set Elm.ProjectStatus.CodeReferenceKey 39 | , callgraph : Dict FilePath (List Elm.CallGraph.Node) 40 | , facts : Dict FilePath (List Ports.Fact) 41 | } 42 | 43 | 44 | type alias FilePath = 45 | String 46 | 47 | 48 | type Viewing 49 | = ViewingProjectList 50 | | ViewingProject Elm.ProjectStatus.Project 51 | 52 | 53 | type Msg 54 | = Incoming (Result Decode.Error Ports.Incoming) 55 | | View Viewing 56 | | AnswerReceived (Result Http.Error Question.Answer) 57 | -- Editor actions 58 | | EditorGoTo FilePath Editor.Region 59 | | EditorFillTypeSignatures FilePath 60 | -- 61 | | ErrorMenuUpdated Bool 62 | | ErrorCodeToggled Elm.ProjectStatus.CodeReferenceKey Bool 63 | | CurrentTime Time.Posix 64 | -- Window messages 65 | | WindowMaximizeClicked 66 | | WindowMinimizeClicked 67 | | WindowCloseClicked 68 | -------------------------------------------------------------------------------- /apps/app/src/Ui/Card.elm: -------------------------------------------------------------------------------- 1 | module Ui.Card exposing (view) 2 | 3 | {-| -} 4 | 5 | import Element as Ui 6 | import Element.Border as Border 7 | import Element.Events as Events 8 | import Element.Font as Font 9 | import Element.Keyed as Keyed 10 | import Ui 11 | 12 | 13 | view : 14 | { title : String 15 | , hint : Maybe String 16 | , highlight : Bool 17 | , onClick : Maybe msg 18 | } 19 | -> List (Ui.Element msg) 20 | -> Ui.Element msg 21 | view options content = 22 | Ui.column 23 | [ Ui.width Ui.fill 24 | , Ui.space.lg 25 | , Ui.pad.xl 26 | , Ui.rounded.md 27 | , Ui.background.dark 28 | , if options.highlight then 29 | Ui.border.dark.light 30 | 31 | else 32 | Ui.border.dark.medium 33 | , Border.width 1 34 | , Ui.maybeAttr (Maybe.map Events.onClick options.onClick) 35 | , Ui.maybeAttr (Maybe.map (\_ -> Ui.pointer) options.onClick) 36 | ] 37 | (viewHeader options :: content) 38 | 39 | 40 | viewHeader : { a | hint : Maybe String, title : String } -> Ui.Element msg 41 | viewHeader options = 42 | Ui.row [ Ui.space.md, Ui.width Ui.fill ] 43 | [ Ui.el [] 44 | (Ui.text (String.trim options.title)) 45 | , Ui.whenJust options.hint <| 46 | \text -> 47 | Ui.el 48 | [ Ui.font.dark.light 49 | , Ui.alignRight 50 | ] 51 | (Ui.text text) 52 | ] 53 | -------------------------------------------------------------------------------- /apps/elm-dev/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /apps/elm-dev/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["tauri-apps.tauri-vscode", "rust-lang.rust-analyzer"] 3 | } 4 | -------------------------------------------------------------------------------- /apps/elm-dev/README.md: -------------------------------------------------------------------------------- 1 | # Tauri + Vanilla TS 2 | 3 | This template should help get you started developing with Tauri in vanilla HTML, CSS and Typescript. 4 | 5 | ## Recommended IDE Setup 6 | 7 | - [VS Code](https://code.visualstudio.com/) + [Tauri](https://marketplace.visualstudio.com/items?itemName=tauri-apps.tauri-vscode) + [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer) 8 | -------------------------------------------------------------------------------- /apps/elm-dev/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Elm Dev 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /apps/elm-dev/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "elm-dev", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "preview": "vite preview", 10 | "tauri": "tauri" 11 | }, 12 | "dependencies": { 13 | "@tauri-apps/api": "2.0.0-rc.2", 14 | "@tauri-apps/plugin-http": "2.0.0-rc.1", 15 | "@tauri-apps/plugin-os": "2.0.0-rc.0", 16 | "@tauri-apps/plugin-positioner": "2.0.0-rc.0", 17 | "@tauri-apps/plugin-shell": "2.0.0-rc.0", 18 | "@types/node": "^22.15.19" 19 | }, 20 | "devDependencies": { 21 | "@tauri-apps/cli": "2.0.0-rc.5", 22 | "typescript": "^5.0.2", 23 | "vite": "^5.0.0", 24 | "vite-plugin-elm": "^3.0.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /apps/elm-dev/src-tauri/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | -------------------------------------------------------------------------------- /apps/elm-dev/src-tauri/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "elm-dev" 3 | version = "0.0.0" 4 | description = "A Tauri App" 5 | authors = ["you"] 6 | license = "" 7 | repository = "" 8 | edition = "2021" 9 | 10 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 11 | 12 | [build-dependencies] 13 | tauri-build = { version = "2.0.0-rc", features = [] } 14 | 15 | [dependencies] 16 | tauri = { version = "2.0.0-rc", features = ["macos-private-api", "tray-icon"] } 17 | tauri-plugin-positioner = { version = "2.0.0-rc", features = ["tray-icon"] } 18 | tauri-plugin-shell = "2.0.0-rc.2" 19 | tauri-plugin-os = "2.0.0-rc.0" 20 | tauri-plugin-http = "2.0.0-rc.0" 21 | 22 | serde = { version = "1.0", features = ["derive"] } 23 | serde_json = "1.0" 24 | 25 | 26 | [features] 27 | # this feature is used for production builds or when `devPath` points to the filesystem 28 | # DO NOT REMOVE!! 29 | custom-protocol = ["tauri/custom-protocol"] 30 | 31 | 32 | [lib] 33 | name = "app_lib" 34 | crate-type = ["lib", "cdylib", "staticlib"] 35 | -------------------------------------------------------------------------------- /apps/elm-dev/src-tauri/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | tauri_build::build() 3 | } 4 | -------------------------------------------------------------------------------- /apps/elm-dev/src-tauri/capabilities/migrated.json: -------------------------------------------------------------------------------- 1 | { 2 | "identifier": "migrated", 3 | "description": "permissions that were migrated from v1", 4 | "local": true, 5 | "windows": ["main"], 6 | "permissions": [ 7 | "core:default", 8 | "core:window:allow-maximize", 9 | "core:window:allow-unmaximize", 10 | "core:window:allow-minimize", 11 | "core:window:allow-unminimize", 12 | "core:window:allow-show", 13 | "core:window:allow-hide", 14 | "core:window:allow-close", 15 | "core:window:allow-start-dragging", 16 | "shell:allow-open", 17 | "http:default", 18 | "os:allow-platform", 19 | "os:allow-version", 20 | "os:allow-os-type", 21 | "os:allow-family", 22 | "os:allow-arch", 23 | "os:allow-exe-extension", 24 | "os:allow-locale", 25 | "os:allow-hostname", 26 | "shell:default", 27 | "os:default", 28 | "http:default", 29 | "positioner:default" 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /apps/elm-dev/src-tauri/gen/schemas/capabilities.json: -------------------------------------------------------------------------------- 1 | {"migrated":{"identifier":"migrated","description":"permissions that were migrated from v1","local":true,"windows":["main"],"permissions":["core:default","core:window:allow-maximize","core:window:allow-unmaximize","core:window:allow-minimize","core:window:allow-unminimize","core:window:allow-show","core:window:allow-hide","core:window:allow-close","core:window:allow-start-dragging","shell:allow-open","http:default","os:allow-platform","os:allow-version","os:allow-os-type","os:allow-family","os:allow-arch","os:allow-exe-extension","os:allow-locale","os:allow-hostname","shell:default","os:default","http:default","positioner:default"]}} -------------------------------------------------------------------------------- /apps/elm-dev/src-tauri/icons/128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/apps/elm-dev/src-tauri/icons/128x128.png -------------------------------------------------------------------------------- /apps/elm-dev/src-tauri/icons/128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/apps/elm-dev/src-tauri/icons/128x128@2x.png -------------------------------------------------------------------------------- /apps/elm-dev/src-tauri/icons/32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/apps/elm-dev/src-tauri/icons/32x32.png -------------------------------------------------------------------------------- /apps/elm-dev/src-tauri/icons/Square107x107Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/apps/elm-dev/src-tauri/icons/Square107x107Logo.png -------------------------------------------------------------------------------- /apps/elm-dev/src-tauri/icons/Square142x142Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/apps/elm-dev/src-tauri/icons/Square142x142Logo.png -------------------------------------------------------------------------------- /apps/elm-dev/src-tauri/icons/Square150x150Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/apps/elm-dev/src-tauri/icons/Square150x150Logo.png -------------------------------------------------------------------------------- /apps/elm-dev/src-tauri/icons/Square284x284Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/apps/elm-dev/src-tauri/icons/Square284x284Logo.png -------------------------------------------------------------------------------- /apps/elm-dev/src-tauri/icons/Square30x30Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/apps/elm-dev/src-tauri/icons/Square30x30Logo.png -------------------------------------------------------------------------------- /apps/elm-dev/src-tauri/icons/Square310x310Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/apps/elm-dev/src-tauri/icons/Square310x310Logo.png -------------------------------------------------------------------------------- /apps/elm-dev/src-tauri/icons/Square44x44Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/apps/elm-dev/src-tauri/icons/Square44x44Logo.png -------------------------------------------------------------------------------- /apps/elm-dev/src-tauri/icons/Square71x71Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/apps/elm-dev/src-tauri/icons/Square71x71Logo.png -------------------------------------------------------------------------------- /apps/elm-dev/src-tauri/icons/Square89x89Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/apps/elm-dev/src-tauri/icons/Square89x89Logo.png -------------------------------------------------------------------------------- /apps/elm-dev/src-tauri/icons/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/apps/elm-dev/src-tauri/icons/StoreLogo.png -------------------------------------------------------------------------------- /apps/elm-dev/src-tauri/icons/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/apps/elm-dev/src-tauri/icons/icon.icns -------------------------------------------------------------------------------- /apps/elm-dev/src-tauri/icons/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/apps/elm-dev/src-tauri/icons/icon.ico -------------------------------------------------------------------------------- /apps/elm-dev/src-tauri/icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/apps/elm-dev/src-tauri/icons/icon.png -------------------------------------------------------------------------------- /apps/elm-dev/src-tauri/src/main.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] 2 | 3 | fn main() { 4 | app_lib::run(); 5 | } 6 | -------------------------------------------------------------------------------- /apps/elm-dev/src-tauri/tauri.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "build": { 3 | "beforeDevCommand": "bun run dev", 4 | "beforeBuildCommand": "bun run build", 5 | "frontendDist": "../dist", 6 | "devUrl": "http://localhost:1420" 7 | }, 8 | "bundle": { 9 | "active": true, 10 | "targets": "all", 11 | "icon": [ 12 | "icons/32x32.png", 13 | "icons/128x128.png", 14 | "icons/128x128@2x.png", 15 | "icons/icon.icns", 16 | "icons/icon.ico" 17 | ] 18 | }, 19 | "productName": "Elm Dev", 20 | "version": "0.0.0", 21 | "identifier": "elm.dev", 22 | "plugins": {}, 23 | "app": { 24 | "macOSPrivateApi": true, 25 | "windows": [ 26 | { 27 | "fullscreen": false, 28 | "resizable": true, 29 | "title": "Elm Dev", 30 | "width": 800, 31 | "height": 1200, 32 | "titleBarStyle": "Overlay", 33 | "alwaysOnTop": true, 34 | "decorations": false, 35 | "transparent": true 36 | } 37 | ], 38 | "withGlobalTauri": true, 39 | "trayIcon": { 40 | "iconPath": "icons/icon.png", 41 | "iconAsTemplate": true 42 | }, 43 | "security": { 44 | "csp": null 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /apps/elm-dev/src/assets/typescript.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 10 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /apps/elm-dev/src/assets/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/elm-dev/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "module": "ESNext", 6 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "noEmit": true, 15 | 16 | /* Linting */ 17 | "strict": true, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "noFallthroughCasesInSwitch": true 21 | }, 22 | "include": ["src"] 23 | } 24 | -------------------------------------------------------------------------------- /apps/elm-dev/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | // @ts-ignore 3 | import elmPlugin from "vite-plugin-elm"; 4 | 5 | const host = process.env.TAURI_DEV_HOST; 6 | 7 | // https://vitejs.dev/config/ 8 | export default defineConfig(async ({ mode }) => { 9 | const isDev = mode == "development"; 10 | return { 11 | // Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build` 12 | // 13 | // 1. prevent vite from obscuring rust errors 14 | clearScreen: false, 15 | // 2. tauri expects a fixed port, fail if that port is not available 16 | server: { 17 | port: 1420, 18 | strictPort: true, 19 | // if the host Tauri is expecting is set, use it 20 | host: host || false, 21 | 22 | hmr: host 23 | ? { 24 | protocol: 'ws', 25 | host, 26 | port: 1421, 27 | } 28 | : undefined, 29 | 30 | 31 | watch: { 32 | // 3. tell vite to ignore watching `src-tauri` 33 | ignored: ["**/src-tauri/**"], 34 | // Watch the elm app 35 | additionalPaths: ["../app/src/**"], 36 | }, 37 | }, 38 | // Env variables starting with the item of `envPrefix` will be exposed in tauri's source code through `import.meta.env`. 39 | envPrefix: ['VITE_', 'TAURI_ENV_*'], 40 | 41 | plugins: [ 42 | elmPlugin({ 43 | debug: isDev, 44 | optimize: !isDev, 45 | }), 46 | ], 47 | }; 48 | }); 49 | -------------------------------------------------------------------------------- /apps/elm-dev2/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /apps/elm-dev2/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["tauri-apps.tauri-vscode", "rust-lang.rust-analyzer"] 3 | } 4 | -------------------------------------------------------------------------------- /apps/elm-dev2/README.md: -------------------------------------------------------------------------------- 1 | # Tauri + Vanilla TS 2 | 3 | This template should help get you started developing with Tauri in vanilla HTML, CSS and Typescript. 4 | 5 | ## Recommended IDE Setup 6 | 7 | - [VS Code](https://code.visualstudio.com/) + [Tauri](https://marketplace.visualstudio.com/items?itemName=tauri-apps.tauri-vscode) + [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer) 8 | -------------------------------------------------------------------------------- /apps/elm-dev2/elm.generate.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": { 3 | "pages": { 4 | "Home": "/", 5 | "Guide": "/guide/*", 6 | "Module": "/module/*", 7 | "Reference": "/ref", 8 | "Package": "/package/*" 9 | } 10 | }, 11 | "assets": { 12 | "Assets": { 13 | "onServer": "assets", 14 | "src": "./public" 15 | } 16 | }, 17 | "packageManager": "bun" 18 | } -------------------------------------------------------------------------------- /apps/elm-dev2/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "src/app", 5 | "elm-stuff/generated" 6 | ], 7 | "elm-version": "0.19.1", 8 | "dependencies": { 9 | "direct": { 10 | "avh4/elm-color": "1.0.0", 11 | "dillonkearns/elm-markdown": "7.0.1", 12 | "elm/browser": "1.0.2", 13 | "elm/bytes": "1.0.8", 14 | "elm/core": "1.0.5", 15 | "elm/file": "1.0.5", 16 | "elm/html": "1.0.0", 17 | "elm/http": "2.0.0", 18 | "elm/json": "1.1.3", 19 | "elm/project-metadata-utils": "1.0.2", 20 | "elm/random": "1.0.0", 21 | "elm/time": "1.0.0", 22 | "elm/url": "1.0.0", 23 | "elm/virtual-dom": "1.0.3", 24 | "lydell/elm-app-url": "1.0.4", 25 | "mdgriffith/elm-bezier": "1.0.0" 26 | }, 27 | "indirect": { 28 | "elm/parser": "1.1.0", 29 | "elm/regex": "1.0.0", 30 | "rtfeldman/elm-hex": "1.0.0" 31 | } 32 | }, 33 | "test-dependencies": { 34 | "direct": {}, 35 | "indirect": {} 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /apps/elm-dev2/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Tauri App 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /apps/elm-dev2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "elm-dev", 3 | "private": true, 4 | "version": "0.1.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "preview": "vite preview", 10 | "tauri": "tauri" 11 | }, 12 | "dependencies": { 13 | "@tauri-apps/api": "^2", 14 | "@tauri-apps/plugin-opener": "^2" 15 | }, 16 | "devDependencies": { 17 | "@tauri-apps/cli": "^2", 18 | "@types/node": "^22.15.21", 19 | "launch-editor": "^2.10.0", 20 | "typescript": "~5.6.2", 21 | "vite": "^6.0.3" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /apps/elm-dev2/src-tauri/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Generated by Tauri 6 | # will have schema files for capabilities auto-completion 7 | /gen/schemas 8 | -------------------------------------------------------------------------------- /apps/elm-dev2/src-tauri/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "elm-dev" 3 | version = "0.1.0" 4 | description = "A Tauri App" 5 | authors = ["you"] 6 | edition = "2021" 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [lib] 11 | # The `_lib` suffix may seem redundant but it is necessary 12 | # to make the lib name unique and wouldn't conflict with the bin name. 13 | # This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519 14 | name = "elm_dev_lib" 15 | crate-type = ["staticlib", "cdylib", "rlib"] 16 | 17 | [build-dependencies] 18 | tauri-build = { version = "2", features = [] } 19 | 20 | [dependencies] 21 | tauri = { version = "2", features = [] } 22 | tauri-plugin-opener = "2" 23 | serde = { version = "1", features = ["derive"] } 24 | serde_json = "1" 25 | 26 | -------------------------------------------------------------------------------- /apps/elm-dev2/src-tauri/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | tauri_build::build() 3 | } 4 | -------------------------------------------------------------------------------- /apps/elm-dev2/src-tauri/capabilities/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../gen/schemas/desktop-schema.json", 3 | "identifier": "default", 4 | "description": "Capability for the main window", 5 | "windows": ["main"], 6 | "permissions": [ 7 | "core:default", 8 | "opener:default" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /apps/elm-dev2/src-tauri/icons/128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/apps/elm-dev2/src-tauri/icons/128x128.png -------------------------------------------------------------------------------- /apps/elm-dev2/src-tauri/icons/128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/apps/elm-dev2/src-tauri/icons/128x128@2x.png -------------------------------------------------------------------------------- /apps/elm-dev2/src-tauri/icons/32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/apps/elm-dev2/src-tauri/icons/32x32.png -------------------------------------------------------------------------------- /apps/elm-dev2/src-tauri/icons/Square107x107Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/apps/elm-dev2/src-tauri/icons/Square107x107Logo.png -------------------------------------------------------------------------------- /apps/elm-dev2/src-tauri/icons/Square142x142Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/apps/elm-dev2/src-tauri/icons/Square142x142Logo.png -------------------------------------------------------------------------------- /apps/elm-dev2/src-tauri/icons/Square150x150Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/apps/elm-dev2/src-tauri/icons/Square150x150Logo.png -------------------------------------------------------------------------------- /apps/elm-dev2/src-tauri/icons/Square284x284Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/apps/elm-dev2/src-tauri/icons/Square284x284Logo.png -------------------------------------------------------------------------------- /apps/elm-dev2/src-tauri/icons/Square30x30Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/apps/elm-dev2/src-tauri/icons/Square30x30Logo.png -------------------------------------------------------------------------------- /apps/elm-dev2/src-tauri/icons/Square310x310Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/apps/elm-dev2/src-tauri/icons/Square310x310Logo.png -------------------------------------------------------------------------------- /apps/elm-dev2/src-tauri/icons/Square44x44Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/apps/elm-dev2/src-tauri/icons/Square44x44Logo.png -------------------------------------------------------------------------------- /apps/elm-dev2/src-tauri/icons/Square71x71Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/apps/elm-dev2/src-tauri/icons/Square71x71Logo.png -------------------------------------------------------------------------------- /apps/elm-dev2/src-tauri/icons/Square89x89Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/apps/elm-dev2/src-tauri/icons/Square89x89Logo.png -------------------------------------------------------------------------------- /apps/elm-dev2/src-tauri/icons/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/apps/elm-dev2/src-tauri/icons/StoreLogo.png -------------------------------------------------------------------------------- /apps/elm-dev2/src-tauri/icons/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/apps/elm-dev2/src-tauri/icons/icon.icns -------------------------------------------------------------------------------- /apps/elm-dev2/src-tauri/icons/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/apps/elm-dev2/src-tauri/icons/icon.ico -------------------------------------------------------------------------------- /apps/elm-dev2/src-tauri/icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/apps/elm-dev2/src-tauri/icons/icon.png -------------------------------------------------------------------------------- /apps/elm-dev2/src-tauri/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Learn more about Tauri commands at https://tauri.app/develop/calling-rust/ 2 | #[tauri::command] 3 | fn greet(name: &str) -> String { 4 | format!("Hello, {}! You've been greeted from Rust!", name) 5 | } 6 | 7 | #[cfg_attr(mobile, tauri::mobile_entry_point)] 8 | pub fn run() { 9 | tauri::Builder::default() 10 | .plugin(tauri_plugin_opener::init()) 11 | .invoke_handler(tauri::generate_handler![greet]) 12 | .run(tauri::generate_context!()) 13 | .expect("error while running tauri application"); 14 | } 15 | -------------------------------------------------------------------------------- /apps/elm-dev2/src-tauri/src/main.rs: -------------------------------------------------------------------------------- 1 | // Prevents additional console window on Windows in release, DO NOT REMOVE!! 2 | #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] 3 | 4 | fn main() { 5 | elm_dev_lib::run() 6 | } 7 | -------------------------------------------------------------------------------- /apps/elm-dev2/src-tauri/tauri.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.tauri.app/config/2", 3 | "productName": "elm-dev", 4 | "version": "0.1.0", 5 | "identifier": "com.elm-dev.app", 6 | "build": { 7 | "beforeDevCommand": "bun run dev", 8 | "devUrl": "http://localhost:1420", 9 | "beforeBuildCommand": "bun run build", 10 | "frontendDist": "../dist" 11 | }, 12 | "app": { 13 | "withGlobalTauri": true, 14 | "windows": [ 15 | { 16 | "title": "elm-dev", 17 | "width": 800, 18 | "height": 600 19 | } 20 | ], 21 | "security": { 22 | "csp": null 23 | } 24 | }, 25 | "bundle": { 26 | "active": true, 27 | "targets": "all", 28 | "icon": [ 29 | "icons/32x32.png", 30 | "icons/128x128.png", 31 | "icons/128x128@2x.png", 32 | "icons/icon.icns", 33 | "icons/icon.ico" 34 | ] 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /apps/elm-dev2/src/app/Broadcast.elm: -------------------------------------------------------------------------------- 1 | module Broadcast exposing (Msg(..)) 2 | 3 | {-| This is a module that is special for elm-prefab. 4 | 5 | The `Msg` here can be broadcasted globally to any page that is listening. 6 | 7 | To broadcast a message, you'd do this in your `update` function: 8 | 9 | Effect.broadcast Broadcast.LogOut 10 | 11 | And to listen for this message, in your subscriptions, you'd have 12 | 13 | Listen.onBroadcast 14 | (\broadcastMsg -> 15 | case broadcastMsg of 16 | Broadcast.LogOut -> 17 | -- You can choose which messages you opt in to. 18 | Nothing 19 | ) 20 | 21 | @docs Msg 22 | 23 | -} 24 | 25 | import Docs.Ref 26 | 27 | 28 | type Msg 29 | = RefPinned Docs.Ref.Ref 30 | -------------------------------------------------------------------------------- /apps/elm-dev2/src/app/Docs/Ref.elm: -------------------------------------------------------------------------------- 1 | module Docs.Ref exposing 2 | ( Id(..) 3 | , Ref 4 | ) 5 | 6 | import Elm.Docs 7 | import Elm.Module 8 | import Elm.Package 9 | 10 | 11 | type alias Ref = 12 | { id : Id 13 | , source : Source 14 | , block : Elm.Docs.Block 15 | } 16 | 17 | 18 | type Id 19 | = Id String 20 | 21 | 22 | type alias Source = 23 | { moduleName : Elm.Module.Name 24 | , package : Elm.Package.Name 25 | } 26 | -------------------------------------------------------------------------------- /apps/elm-dev2/src/app/Flags.elm: -------------------------------------------------------------------------------- 1 | module Flags exposing 2 | ( Flags 3 | , Platform(..) 4 | , decoder 5 | ) 6 | 7 | import Json.Decode as Decode 8 | 9 | 10 | type alias Flags = 11 | { platform : Platform 12 | } 13 | 14 | 15 | type Platform 16 | = Windows 17 | | Mac 18 | | Linux 19 | | VSCode 20 | 21 | 22 | decoder : Decode.Decoder Flags 23 | decoder = 24 | Decode.map Flags 25 | (Decode.field "platform" platformDecoder) 26 | 27 | 28 | {-| 29 | 30 | List is taken from here: https://tauri.app/v1/api/js/os 31 | 32 | 'linux', 'darwin', 'ios', 'freebsd', 'dragonfly', 'netbsd', 'openbsd', 'solaris', 'android', 'win32' 33 | 34 | But we also add in VSCode. 35 | 36 | -} 37 | platformDecoder : Decode.Decoder Platform 38 | platformDecoder = 39 | Decode.string 40 | |> Decode.andThen 41 | (\str -> 42 | case str of 43 | "win32" -> 44 | Decode.succeed Windows 45 | 46 | "darwin" -> 47 | Decode.succeed Mac 48 | 49 | "macos" -> 50 | Decode.succeed Mac 51 | 52 | "vscode" -> 53 | Decode.succeed VSCode 54 | 55 | _ -> 56 | Decode.succeed Linux 57 | ) 58 | -------------------------------------------------------------------------------- /apps/elm-dev2/src/app/Page/Home.elm: -------------------------------------------------------------------------------- 1 | module Page.Home exposing (page, Model, Msg) 2 | 3 | {-| 4 | 5 | @docs page, Model, Msg 6 | 7 | -} 8 | 9 | import App.Page 10 | import App.Page.Id 11 | import App.Route 12 | import App.Stores 13 | import App.View 14 | import App.View.Region 15 | import Effect exposing (Effect) 16 | import Html 17 | import Listen exposing (Listen) 18 | 19 | 20 | {-| -} 21 | type alias Model = 22 | {} 23 | 24 | 25 | {-| -} 26 | type Msg 27 | = ReplaceMe 28 | 29 | 30 | page : App.Page.Page App.Stores.Stores App.Page.Id.Home_Params Msg Model 31 | page = 32 | App.Page.page 33 | { init = init 34 | , update = update 35 | , subscriptions = subscriptions 36 | , view = view 37 | } 38 | 39 | 40 | init : App.Page.Id.Id -> App.Page.Id.Home_Params -> App.Stores.Stores -> Maybe Model -> App.Page.Init Msg Model 41 | init pageId params shared maybeCached = 42 | App.Page.init {} 43 | 44 | 45 | update : App.Stores.Stores -> Msg -> Model -> ( Model, Effect Msg ) 46 | update shared msg model = 47 | ( model, Effect.none ) 48 | 49 | 50 | subscriptions : App.Stores.Stores -> Model -> Listen Msg 51 | subscriptions shared model = 52 | Listen.none 53 | 54 | 55 | view : App.View.Region.Id -> App.Stores.Stores -> Model -> App.View.View Msg 56 | view viewId shared model = 57 | { title = "Directory" 58 | , body = viewPackages 59 | } 60 | 61 | 62 | viewPackages = 63 | Html.div [] 64 | [ Html.h1 [] [ Html.text "Packages" ] 65 | ] 66 | -------------------------------------------------------------------------------- /apps/elm-dev2/src/app/Ui.elm: -------------------------------------------------------------------------------- 1 | module Ui exposing (column, row) 2 | 3 | {-| -} 4 | 5 | import Html exposing (Html) 6 | import Html.Attributes as Attr 7 | 8 | 9 | column : List (Html.Attribute msg) -> List (Html msg) -> Html msg 10 | column attrs children = 11 | Html.div (Attr.class "column" :: attrs) children 12 | 13 | 14 | row : List (Html.Attribute msg) -> List (Html msg) -> Html msg 15 | row attrs children = 16 | Html.div (Attr.class "row" :: attrs) children 17 | -------------------------------------------------------------------------------- /apps/elm-dev2/src/app/Ui/Markdown.elm: -------------------------------------------------------------------------------- 1 | module Ui.Markdown exposing (view) 2 | 3 | import Html exposing (Html) 4 | import Html.Attributes 5 | import Markdown.Parser 6 | import Markdown.Renderer 7 | 8 | 9 | view : String -> Html msg 10 | view markdown = 11 | let 12 | parsedResult = 13 | Markdown.Parser.parse markdown 14 | in 15 | case parsedResult of 16 | Err _ -> 17 | Html.div 18 | [ Html.Attributes.class "markdown" ] 19 | [ Html.text "Error parsing markdown" ] 20 | 21 | Ok parsed -> 22 | Html.div 23 | [ Html.Attributes.class "markdown" ] 24 | (case Markdown.Renderer.render Markdown.Renderer.defaultHtmlRenderer parsed of 25 | Err errString -> 26 | [ Html.text errString ] 27 | 28 | Ok rendered -> 29 | rendered 30 | ) 31 | -------------------------------------------------------------------------------- /apps/elm-dev2/src/app/Ui/Syntax.elm: -------------------------------------------------------------------------------- 1 | module Ui.Syntax exposing (field, keyword, punctuation, type_, typevar) 2 | 3 | import Html 4 | import Html.Attributes as Attr 5 | 6 | 7 | typevar : Html.Attribute msg 8 | typevar = 9 | Attr.class "typevar" 10 | 11 | 12 | punctuation : Html.Attribute msg 13 | punctuation = 14 | Attr.class "punctuation" 15 | 16 | 17 | type_ : Html.Attribute msg 18 | type_ = 19 | Attr.class "type" 20 | 21 | 22 | field : Html.Attribute msg 23 | field = 24 | Attr.class "field" 25 | 26 | 27 | keyword : Html.Attribute msg 28 | keyword = 29 | Attr.class "keyword" 30 | -------------------------------------------------------------------------------- /apps/elm-dev2/src/assets/typescript.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 10 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /apps/elm-dev2/src/assets/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/elm-dev2/src/js/effect/clipboard.ts: -------------------------------------------------------------------------------- 1 | export const connect = (app: any, data: any) => { 2 | app.ports?.clipboard?.subscribe?.((message: any) => { 3 | copy(message); 4 | }); 5 | }; 6 | 7 | 8 | export function copy(text: string) { 9 | const clipboard = navigator.clipboard; 10 | if (!clipboard) { 11 | return; 12 | } 13 | clipboard.writeText(text); 14 | } 15 | -------------------------------------------------------------------------------- /apps/elm-dev2/src/js/effect/local-storage.ts: -------------------------------------------------------------------------------- 1 | export const connect = (app: any, data: any) => { 2 | // Listen for messages from Elm 3 | app.ports?.localStorage?.subscribe?.((message: any) => { 4 | switch (message.operation) { 5 | case "save": 6 | set(message.details.key, message.details.value); 7 | if (app.ports?.localStorageUpdated) { 8 | app.ports.localStorageUpdated.send(message.details); 9 | } 10 | break; 11 | 12 | case "clear": 13 | clear(message.details.key); 14 | break; 15 | 16 | default: 17 | break; 18 | } 19 | }); 20 | }; 21 | 22 | 23 | // Actual commands 24 | export const getAll = () => { 25 | const data: any = {}; 26 | for (var i = 0, len = localStorage.length; i < len; ++i) { 27 | const key = localStorage.key(i); 28 | if (key) { 29 | data[key] = get(key); 30 | } 31 | } 32 | return data; 33 | }; 34 | 35 | export const get = (key: string): any => { 36 | const item = localStorage.getItem(key); 37 | if (item) { 38 | try { 39 | return JSON.parse(item); 40 | } catch (e) { 41 | return null; 42 | } 43 | } else { 44 | return null; 45 | } 46 | }; 47 | 48 | export const set = (key: string, value: any) => { 49 | localStorage.setItem(key, JSON.stringify(value)); 50 | }; 51 | 52 | export const clear = (key: string) => { 53 | localStorage.removeItem(key); 54 | }; 55 | -------------------------------------------------------------------------------- /apps/elm-dev2/src/js/effect/scroll.ts: -------------------------------------------------------------------------------- 1 | export const connect = (app: any, data: any) => { 2 | // Listen for messages from Elm 3 | app.ports?.resetWindowScroll?.subscribe?.(() => { 4 | window.scrollTo(0, 0); 5 | }); 6 | }; 7 | -------------------------------------------------------------------------------- /apps/elm-dev2/src/js/effect/text-selection.ts: -------------------------------------------------------------------------------- 1 | export const connect = (app: any, data: any) => { 2 | // Listen for messages from Elm 3 | app.ports?.textSelection?.subscribe?.((message: any) => { 4 | focus_and_select(message.id); 5 | }); 6 | }; 7 | 8 | 9 | 10 | export function focus_and_select(id: string) { 11 | setTimeout(() => { 12 | // in some cases the element hasn't been rendered yet 13 | const elem = document.getElementById(id); 14 | if (elem) { 15 | elem.focus(); 16 | (elem as HTMLInputElement).select(); 17 | } 18 | }, 100); 19 | } 20 | -------------------------------------------------------------------------------- /apps/elm-dev2/src/js/effects.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | // This imports all effect modules in the effect directory 4 | // and calls connect on them. 5 | export function connect(app: any, data: any) { 6 | const modules = import.meta.glob("./effect/*.ts", { eager: true }); 7 | for (const module of Object.values(modules)) { 8 | if ("connect" in module && module.connect && typeof module.connect === 'function') { 9 | module.connect(app, data); 10 | } else { 11 | console.log(`${module} does not have a connect function`); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /apps/elm-dev2/src/js/util/json.ts: -------------------------------------------------------------------------------- 1 | export const safeParse = (source: string) => { 2 | try { 3 | return JSON.parse(source); 4 | } catch (err) { 5 | console.log("Error parsing watchtower Msg:"); 6 | console.log(" " + err); 7 | console.log("Original Msg"); 8 | console.log(source); 9 | return null; 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /apps/elm-dev2/src/js/webcomponents/index.ts: -------------------------------------------------------------------------------- 1 | // import TipTap from "./js/tiptap"; 2 | import ElmPortal from "./elm-portal"; 3 | import ElmDev from "./interactive"; 4 | 5 | export default function include() { 6 | ElmPortal({ mountId: "elm-portal-target" }); 7 | ElmDev(); 8 | // TipTap(); 9 | } 10 | -------------------------------------------------------------------------------- /apps/elm-dev2/src/main.ts: -------------------------------------------------------------------------------- 1 | // @ts-expect-error 2 | import Main from "./src/app/Main.elm"; 3 | import * as LocalStorage from "./js/effect/local-storage"; 4 | import * as Effects from "./js/effects"; 5 | import Webcomponents from "./js/webcomponents"; 6 | import * as JSON from "./js/util/json"; 7 | 8 | // Mount Elm App 9 | // Import all generated CSS files 10 | import.meta.glob("../elm-stuff/generated/**/*.css", { eager: true }); 11 | 12 | // Include any custom elements we need. 13 | Webcomponents(); 14 | 15 | // Boot up the Elm App 16 | const app = Main.init({ 17 | flags: { now: Date.now(), localStorage: LocalStorage.getAll() }, 18 | }); 19 | 20 | // Connect all effects 21 | Effects.connect(app, {}); 22 | 23 | // Connect listeners 24 | const domain = "localhost"; 25 | const port = "51213"; 26 | const websocket = new WebSocket(`ws://${domain}:${port}/ws`); 27 | 28 | websocket.onopen = () => { 29 | console.log("Connected to websocket"); 30 | app.ports.devServer.send({ 31 | msg: "Server", 32 | details: { 33 | status: "Connected", 34 | version: "0.1.0", 35 | port: port, 36 | host: domain, 37 | }, 38 | }); 39 | }; 40 | 41 | websocket.onmessage = (event) => { 42 | console.log("Message from Elm Dev", event); 43 | const parsed = JSON.safeParse(event.data); 44 | console.log("Parsed", parsed); 45 | if (parsed == null) { 46 | return; 47 | } 48 | app.ports.devServer.send(parsed); 49 | }; 50 | 51 | websocket.onerror = (event) => { 52 | console.error("Error on websocket", event); 53 | }; 54 | 55 | websocket.onclose = () => { 56 | console.log("Disconnected from websocket"); 57 | }; -------------------------------------------------------------------------------- /apps/elm-dev2/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "module": "ESNext", 6 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "noEmit": true, 15 | 16 | /* Linting */ 17 | "strict": true, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "noFallthroughCasesInSwitch": true 21 | }, 22 | "include": ["src"] 23 | } 24 | -------------------------------------------------------------------------------- /apps/elm-dev2/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import elmDevPlugin from "./elm-dev-vite"; 3 | 4 | const host = process.env.TAURI_DEV_HOST; 5 | 6 | // https://vitejs.dev/config/ 7 | export default defineConfig(async ({ mode }) => { 8 | const isDev = mode == "development"; 9 | return { 10 | 11 | // Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build` 12 | // 13 | // 1. prevent vite from obscuring rust errors 14 | clearScreen: false, 15 | // 2. tauri expects a fixed port, fail if that port is not available 16 | server: { 17 | port: 1420, 18 | strictPort: true, 19 | host: host || false, 20 | hmr: host 21 | ? { 22 | protocol: "ws", 23 | host, 24 | port: 1421, 25 | } 26 | : undefined, 27 | watch: { 28 | // 3. tell vite to ignore watching `src-tauri` 29 | ignored: ["**/src-tauri/**"], 30 | }, 31 | }, 32 | 33 | plugins: [ 34 | elmDevPlugin({ 35 | debug: isDev, 36 | optimize: !isDev, 37 | }), 38 | ], 39 | } 40 | }); 41 | -------------------------------------------------------------------------------- /apps/vscode/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | 63 | 64 | out 65 | 66 | elm-stuff 67 | testProject/index.html -------------------------------------------------------------------------------- /apps/vscode/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to the "elm-watchtower" extension will be documented in this file. 4 | 5 | Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. 6 | 7 | ## [Unreleased] 8 | 9 | - Initial release -------------------------------------------------------------------------------- /apps/vscode/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2022-present Matthew Griffith 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | -------------------------------------------------------------------------------- /apps/vscode/elm.configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | // symbol used for single line comment. Remove this entry if your language does not support line comments 4 | "lineComment": "--", 5 | // symbols used for start and end a block comment. Remove this entry if your language does not support block comments 6 | "blockComment": [ 7 | "{-", 8 | "-}" 9 | ] 10 | }, 11 | // symbols used as brackets 12 | "brackets": [ 13 | [ 14 | "{", 15 | "}" 16 | ], 17 | [ 18 | "[", 19 | "]" 20 | ], 21 | [ 22 | "(", 23 | ")" 24 | ] 25 | ], 26 | "surroundingPairs": [ 27 | [ 28 | "{", 29 | "}" 30 | ], 31 | [ 32 | "[", 33 | "]" 34 | ], 35 | [ 36 | "(", 37 | ")" 38 | ], 39 | [ 40 | "\"", 41 | "\"" 42 | ] 43 | ], 44 | "autoClosingPairs": [ 45 | [ 46 | "(", 47 | ")" 48 | ], 49 | [ 50 | "{", 51 | "}" 52 | ], 53 | [ 54 | "[", 55 | "]" 56 | ], 57 | [ 58 | "\"", 59 | "\"" 60 | ] 61 | ], 62 | "folding": { 63 | "offSide": true 64 | } 65 | } -------------------------------------------------------------------------------- /apps/vscode/media/icons/chevron-right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /apps/vscode/scripts/copy_deps.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | 4 | mkdir -p ./out/interactive 5 | mkdir -p ./out/interactive/src 6 | cp ./src/interactive/elm.json ./out/interactive/elm.json 7 | cp -r ./codegen/helpers/* ./out/interactive/src 8 | cp ./node_modules/elm-format/unpacked_bin/elm-format ./out/elm-format -------------------------------------------------------------------------------- /apps/vscode/src/interactive/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "src", 5 | "/Users/matthewgriffith/projects/mdgriffith/strangeloop-example-app/src" 6 | ], 7 | "elm-version": "0.19.1", 8 | "dependencies": { 9 | "direct": { 10 | "elm/browser": "1.0.2", 11 | "elm/core": "1.0.5", 12 | "elm/html": "1.0.0", 13 | "elm/json": "1.1.3", 14 | "elm/parser": "1.1.0", 15 | "elm/project-metadata-utils": "1.0.2", 16 | "mdgriffith/elm-codegen": "2.0.0", 17 | "mdgriffith/elm-ui": "1.1.8", 18 | "pablohirafuji/elm-syntax-highlight": "3.4.1" 19 | }, 20 | "indirect": { 21 | "elm/regex": "1.0.0", 22 | "elm/time": "1.0.0", 23 | "elm/url": "1.0.0", 24 | "elm/virtual-dom": "1.0.2", 25 | "elm-community/basics-extra": "4.1.0", 26 | "elm-community/list-extra": "8.6.0", 27 | "miniBill/elm-unicode": "1.0.2", 28 | "rtfeldman/elm-hex": "1.0.0", 29 | "stil4m/elm-syntax": "7.2.9", 30 | "stil4m/structured-writer": "1.0.3", 31 | "the-sett/elm-pretty-printer": "3.0.0" 32 | } 33 | }, 34 | "test-dependencies": { 35 | "direct": {}, 36 | "indirect": {} 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /apps/vscode/src/node-elm-compiler.d.ts: -------------------------------------------------------------------------------- 1 | declare module "node-elm-compiler" 2 | -------------------------------------------------------------------------------- /apps/vscode/src/panel/README.md: -------------------------------------------------------------------------------- 1 | The panel is now the Elm app located in apps/app 2 | -------------------------------------------------------------------------------- /apps/vscode/src/utils/editorCoords.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | 3 | export function lineCountDelta(edit) { 4 | const oldLineCount = edit.range.end.line - edit.range.start.line; 5 | const newLineCount = (edit.text.match(/\n/g) || "").length; 6 | return newLineCount - oldLineCount; 7 | } 8 | 9 | /* Note: If this ever gets an invalid region, e.g. a line or column of 0, 10 | * then this will eventually hang forever. and cause regions to not display. 11 | */ 12 | export function regionToRange( 13 | region, 14 | maybeEditsSinceSave: { 15 | uri: vscode.Uri; 16 | edits: vscode.TextDocumentChangeEvent[]; 17 | } | null 18 | ): vscode.Range { 19 | let lineOffset = 0; 20 | if (maybeEditsSinceSave != null) { 21 | const uri = maybeEditsSinceSave.uri; 22 | 23 | for (const edit of maybeEditsSinceSave.edits) { 24 | if (edit.document.uri.fsPath == uri.fsPath) { 25 | for (const change of edit.contentChanges) { 26 | if (change.range.start.line < region.start.line) { 27 | lineOffset += lineCountDelta(change); 28 | } 29 | } 30 | } 31 | } 32 | } 33 | 34 | return new vscode.Range( 35 | Math.max(0, region.start.line - 1 + lineOffset), 36 | Math.max(0, region.start.column - 1), 37 | Math.max(0, region.end.line - 1 + lineOffset), 38 | Math.max(0, region.end.column - 1) 39 | ); 40 | } 41 | -------------------------------------------------------------------------------- /apps/vscode/src/utils/icons.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | export function createIcons(context) { 6 | const icons = 7 | { 8 | error: context.asAbsolutePath('media/icons/chevron-right.svg') 9 | } 10 | return icons 11 | 12 | 13 | } -------------------------------------------------------------------------------- /apps/vscode/src/utils/json.ts: -------------------------------------------------------------------------------- 1 | import * as log from "./log"; 2 | 3 | export const parse = (source: string) => { 4 | try { 5 | return JSON.parse(source); 6 | } catch (err) { 7 | log.log("Error parsing watchtower Msg:"); 8 | log.log(" " + err); 9 | log.log("Original Msg"); 10 | log.log(source); 11 | return null; 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /apps/vscode/src/utils/log.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | 3 | const watchtower = vscode.window.createOutputChannel("Elm Watchtower"); 4 | 5 | export function log(str) { 6 | watchtower.appendLine(str); 7 | } 8 | 9 | 10 | export function obj(name, o) { 11 | watchtower.appendLine(name); 12 | for (const [key, value] of Object.entries(o)) { 13 | 14 | if (Array.isArray(value)) { 15 | let first = true 16 | watchtower.appendLine(" " + key + ":"); 17 | if (value.length == 0) { 18 | watchtower.appendLine(" []"); 19 | } else { 20 | for (const index in value) { 21 | const subval = value[index] 22 | if (first) { 23 | watchtower.appendLine(" [ " + subval); 24 | first = false 25 | } else { 26 | watchtower.appendLine(" , " + subval); 27 | } 28 | 29 | } 30 | watchtower.appendLine(" ]"); 31 | } 32 | } else if ( 33 | typeof value === 'object' && 34 | value !== null 35 | ) { 36 | watchtower.appendLine(" " + key + ": "); 37 | watchtower.appendLine(Object.keys(value).join("\n")); 38 | for (const [subKey, subValue] of Object.entries(value)) { 39 | watchtower.appendLine(" " + subKey + ": " + subValue); 40 | } 41 | 42 | } else { 43 | watchtower.appendLine(" " + key + ": " + value); 44 | } 45 | 46 | } 47 | } 48 | 49 | 50 | -------------------------------------------------------------------------------- /apps/vscode/src/utils/script.ts: -------------------------------------------------------------------------------- 1 | 2 | let spawn = require('cross-spawn'); 3 | 4 | 5 | // opts -> 6 | // { cwd: elmPackageJsonPath, 7 | // env: process.env, 8 | // } 9 | export function executeExpectJson(scriptPath, args, opts) { 10 | return new Promise(function (resolve, reject) { 11 | function finish() { 12 | 13 | var proc = spawn(scriptPath, args, opts); 14 | var jsonStr = ''; 15 | var stderrStr = ''; 16 | 17 | 18 | proc.stdout.on('data', function (data) { 19 | jsonStr += data; 20 | }); 21 | 22 | proc.stderr.on('data', function (data) { 23 | stderrStr += data; 24 | }); 25 | 26 | proc.on('close', function (code) { 27 | if (stderrStr !== '') { 28 | reject(stderrStr); 29 | } else if (code !== 0) { 30 | reject('Finding test interfaces failed, exiting with code ' + code); 31 | } 32 | var parsed; 33 | 34 | try { 35 | if (jsonStr.trim() == ""){ 36 | parsed = null; 37 | } else { 38 | parsed = JSON.parse(jsonStr); 39 | } 40 | } catch (err) { 41 | reject('Received invalid JSON from test interface search: ' + err); 42 | } 43 | 44 | 45 | return resolve(parsed); 46 | }); 47 | } 48 | 49 | return finish(); 50 | }); 51 | } 52 | -------------------------------------------------------------------------------- /apps/vscode/syntaxes/codeblock.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileTypes": [], 3 | "injectionSelector": "L:text.html.markdown", 4 | "patterns": [ 5 | { 6 | "include": "#fenced_code_block_elm" 7 | } 8 | ], 9 | "repository": { 10 | "fenced_code_block_elm": { 11 | "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(elm)(\\s+[^`~]*)?$)", 12 | "name": "markup.fenced_code.block.markdown", 13 | "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", 14 | "beginCaptures": { 15 | "3": { 16 | "name": "punctuation.definition.markdown" 17 | }, 18 | "5": { 19 | "name": "fenced_code.block.language" 20 | }, 21 | "6": { 22 | "name": "fenced_code.block.language.attributes" 23 | } 24 | }, 25 | "endCaptures": { 26 | "3": { 27 | "name": "punctuation.definition.markdown" 28 | } 29 | }, 30 | "patterns": [ 31 | { 32 | "begin": "(^|\\G)(\\s*)(.*)", 33 | "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", 34 | "contentName": "meta.embedded.block.elm", 35 | "patterns": [ 36 | { 37 | "include": "source.elm" 38 | } 39 | ] 40 | } 41 | ] 42 | } 43 | }, 44 | "scopeName": "markdown.elm.codeblock" 45 | } 46 | -------------------------------------------------------------------------------- /apps/vscode/testProject/output/explain.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleName": "Main", 3 | "definition": { 4 | "name": "Regions", 5 | "type": { 6 | "signature": "{ main : view, nav : Maybe view, detail : List view }", 7 | "definition": { 8 | "type": "alias", 9 | "fields": { 10 | "detail": "List view", 11 | "main": "view", 12 | "nav": "Maybe view" 13 | } 14 | }, 15 | "components": [ 16 | { 17 | "source": { 18 | "pkg": "author/project", 19 | "module": "Main" 20 | }, 21 | "definition": { 22 | "type": "alias", 23 | "comment": null, 24 | "module": "Main", 25 | "name": "Regions", 26 | "args": [], 27 | "signature": "{ main : view, nav : Maybe view, detail : List view }", 28 | "fields": { 29 | "detail": "List view", 30 | "main": "view", 31 | "nav": "Maybe view" 32 | } 33 | } 34 | } 35 | ] 36 | }, 37 | "region": { 38 | "start": { 39 | "line": 17, 40 | "column": 1 41 | }, 42 | "end": { 43 | "line": 21, 44 | "column": 6 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /apps/vscode/testProject/output/usage.json: -------------------------------------------------------------------------------- 1 | { 2 | "path": "/Users/mattgriffith/projects/mdgriffith/elm-dev/apps/vscode/testProject/src/Imported.elm", 3 | "usages": [ 4 | { 5 | "name": "MyValue", 6 | "usedBy": [ 7 | "Alias" 8 | ] 9 | }, 10 | { 11 | "name": "sendOtherMessage", 12 | "usedBy": [ 13 | "Main" 14 | ] 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /apps/vscode/testProject/src/Alias.elm: -------------------------------------------------------------------------------- 1 | module Alias exposing (Alias, test) 2 | 3 | import Imported 4 | 5 | 6 | type alias Alias inner = 7 | Imported.MyType inner 8 | 9 | 10 | test : val -> Alias val 11 | test = 12 | Imported.MyValue 13 | -------------------------------------------------------------------------------- /apps/vscode/testProject/src/AlternativeMain.elm: -------------------------------------------------------------------------------- 1 | port module AlternativeMain exposing (main) 2 | 3 | import Browser 4 | import Html as What 5 | import Result 6 | 7 | 8 | type alias Flags = 9 | { flag : String } 10 | 11 | 12 | {-| What is this?? 13 | -} 14 | main : Program Flags Model Msg 15 | main = 16 | Browser.document 17 | { init = \{ flag } -> ( { flag = flag }, Cmd.none ) 18 | , view = 19 | \model -> 20 | { title = "test" 21 | , body = [ What.text model.flag ] 22 | } 23 | , update = update 24 | , subscriptions = 25 | subscriptions 26 | } 27 | 28 | 29 | type alias Model = 30 | { flag : String } 31 | 32 | 33 | type Msg 34 | = NoOp 35 | | Received String 36 | 37 | 38 | update msg model = 39 | case msg of 40 | NoOp -> 41 | ( model, sendMessage model.flag ) 42 | 43 | Received _ -> 44 | ( model, Cmd.none ) 45 | 46 | 47 | port sendMessage : String -> Cmd msg 48 | 49 | 50 | port messageReceiver : (String -> msg) -> Sub msg 51 | 52 | 53 | subscriptions : Model -> Sub Msg 54 | subscriptions model = 55 | messageReceiver Received 56 | 57 | 58 | type alias Otherthing = 59 | { a : String 60 | , b : Int 61 | } 62 | 63 | 64 | type alias Thing var = 65 | { notANextOne : Bool 66 | , aThird : var 67 | } 68 | 69 | 70 | what : String 71 | what = 72 | let 73 | notUsed = 74 | "whoops" 75 | in 76 | "Other thing!" 77 | 78 | 79 | anotherTHing = 80 | 43 81 | 82 | 83 | howAboutARecord = 84 | { notANextOne = True 85 | , aThird = what 86 | } 87 | 88 | 89 | andWhatBoutHere : String 90 | andWhatBoutHere = 91 | "Whaaasat?" 92 | -------------------------------------------------------------------------------- /apps/vscode/testProject/src/Imported.elm: -------------------------------------------------------------------------------- 1 | module Imported exposing (..) 2 | 3 | {-| -} 4 | 5 | import Html as Ui 6 | import NarrativeEngine.Syntax.NarrativeParser 7 | import NarrativeEngine.Syntax.RuleParser 8 | import OtherPorts 9 | 10 | 11 | otherThing : Ui.Html msg 12 | otherThing = 13 | Ui.text "Hello world!" 14 | 15 | 16 | type MyType inner 17 | = MyValue inner 18 | 19 | 20 | sendOtherMessage = 21 | OtherPorts.sendOtherMessage 22 | -------------------------------------------------------------------------------- /apps/vscode/testProject/src/OtherPorts.elm: -------------------------------------------------------------------------------- 1 | port module OtherPorts exposing (sendOtherMessage) 2 | 3 | 4 | port sendOtherMessage : String -> Cmd msg 5 | -------------------------------------------------------------------------------- /apps/vscode/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include":[ 3 | "src/**/*.ts" 4 | ], 5 | "compilerOptions": { 6 | "module": "commonjs", 7 | "target": "es6", 8 | "outDir": "out", 9 | "lib": [ 10 | "es6" 11 | ], 12 | "sourceMap": true, 13 | // "rootDir": "src", 14 | "strict": false, /* enable all strict type-checking options */ 15 | "allowJs": true, 16 | // "esModuleInterop": true, 17 | /* Additional Checks */ 18 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 19 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 20 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 21 | "skipLibCheck": true 22 | }, 23 | "exclude": [ 24 | "node_modules", 25 | ".vscode-test" 26 | ] 27 | } -------------------------------------------------------------------------------- /builder/src/BackgroundWriter.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE BangPatterns #-} 2 | module BackgroundWriter 3 | ( Scope(..) 4 | , withScope 5 | , writeBinary 6 | ) 7 | where 8 | 9 | 10 | import Control.Concurrent (forkIO) 11 | import Control.Concurrent.MVar (MVar, newEmptyMVar, newMVar, putMVar, takeMVar) 12 | import qualified Data.Binary as Binary 13 | import Data.Foldable (traverse_) 14 | 15 | import qualified Ext.FileProxy as File 16 | 17 | 18 | 19 | -- BACKGROUND WRITER 20 | 21 | 22 | newtype Scope = 23 | Scope (MVar [MVar ()]) 24 | 25 | 26 | withScope :: (Scope -> IO a) -> IO a 27 | withScope callback = 28 | do workList <- newMVar [] 29 | result <- callback (Scope workList) 30 | mvars <- takeMVar workList 31 | traverse_ takeMVar mvars 32 | return result 33 | 34 | 35 | writeBinary :: (Binary.Binary a) => Scope -> FilePath -> a -> IO () 36 | writeBinary (Scope workList) path value = 37 | do mvar <- newEmptyMVar 38 | _ <- forkIO (File.writeBinary path value >> putMVar mvar ()) 39 | oldWork <- takeMVar workList 40 | let !newWork = mvar:oldWork 41 | putMVar workList newWork 42 | 43 | -------------------------------------------------------------------------------- /builder/src/Deps/Bump.hs: -------------------------------------------------------------------------------- 1 | module Deps.Bump 2 | ( getPossibilities 3 | ) 4 | where 5 | 6 | 7 | import qualified Data.List as List 8 | 9 | import qualified Deps.Registry as Registry 10 | import qualified Elm.Magnitude as M 11 | import qualified Elm.Version as V 12 | 13 | 14 | 15 | -- GET POSSIBILITIES 16 | 17 | 18 | getPossibilities :: Registry.KnownVersions -> [(V.Version, V.Version, M.Magnitude)] 19 | getPossibilities (Registry.KnownVersions latest previous) = 20 | let 21 | allVersions = reverse (latest:previous) 22 | minorPoints = map last (List.groupBy sameMajor allVersions) 23 | patchPoints = map last (List.groupBy sameMinor allVersions) 24 | in 25 | (latest, V.bumpMajor latest, M.MAJOR) 26 | : map (\v -> (v, V.bumpMinor v, M.MINOR)) minorPoints 27 | ++ map (\v -> (v, V.bumpPatch v, M.PATCH)) patchPoints 28 | 29 | 30 | sameMajor :: V.Version -> V.Version -> Bool 31 | sameMajor (V.Version major1 _ _) (V.Version major2 _ _) = 32 | major1 == major2 33 | 34 | 35 | sameMinor :: V.Version -> V.Version -> Bool 36 | sameMinor (V.Version major1 minor1 _) (V.Version major2 minor2 _) = 37 | major1 == major2 && minor1 == minor2 38 | -------------------------------------------------------------------------------- /builder/src/Deps/Website.hs: -------------------------------------------------------------------------------- 1 | module Deps.Website 2 | ( domain 3 | , route 4 | , metadata 5 | ) 6 | where 7 | 8 | 9 | import qualified Elm.Package as Pkg 10 | import qualified Elm.Version as V 11 | import qualified Http 12 | 13 | 14 | domain :: String 15 | domain = 16 | "https://package.elm-lang.org" 17 | 18 | 19 | route :: String -> [(String,String)] -> String 20 | route path params = 21 | Http.toUrl (domain ++ path) params 22 | 23 | 24 | metadata :: Pkg.Name -> V.Version -> String -> String 25 | metadata name version file = 26 | domain ++ "/packages/" ++ Pkg.toUrl name ++ "/" ++ V.toChars version ++ "/" ++ file 27 | -------------------------------------------------------------------------------- /cabal.config: -------------------------------------------------------------------------------- 1 | profiling: False 2 | library-profiling: True 3 | -------------------------------------------------------------------------------- /cabal.project: -------------------------------------------------------------------------------- 1 | packages: 2 | ./ 3 | -------------------------------------------------------------------------------- /compiler/src/AST/Utils/Binop.hs: -------------------------------------------------------------------------------- 1 | {-# OPTIONS_GHC -Wall #-} 2 | module AST.Utils.Binop 3 | ( Precedence(..) 4 | , Associativity(..) 5 | ) 6 | where 7 | 8 | 9 | import Prelude hiding (Either(..)) 10 | import Control.Monad (liftM) 11 | import Data.Binary 12 | 13 | 14 | 15 | -- BINOP STUFF 16 | 17 | 18 | newtype Precedence = Precedence Int 19 | deriving (Eq, Ord) 20 | 21 | 22 | data Associativity 23 | = Left 24 | | Non 25 | | Right 26 | deriving (Eq) 27 | 28 | 29 | 30 | -- BINARY 31 | 32 | 33 | instance Binary Precedence where 34 | get = 35 | liftM Precedence get 36 | 37 | put (Precedence n) = 38 | put n 39 | 40 | 41 | instance Binary Associativity where 42 | get = 43 | do n <- getWord8 44 | case n of 45 | 0 -> return Left 46 | 1 -> return Non 47 | 2 -> return Right 48 | _ -> fail "Error reading valid associativity from serialized string" 49 | 50 | put assoc = 51 | putWord8 $ 52 | case assoc of 53 | Left -> 0 54 | Non -> 1 55 | Right -> 2 56 | -------------------------------------------------------------------------------- /compiler/src/AST/Utils/Shader.hs: -------------------------------------------------------------------------------- 1 | {-# OPTIONS_GHC -Wall #-} 2 | {-# LANGUAGE EmptyDataDecls #-} 3 | module AST.Utils.Shader 4 | ( Source 5 | , Types(..) 6 | , Type(..) 7 | , fromChars 8 | , toJsStringBuilder 9 | ) 10 | where 11 | 12 | 13 | import Control.Monad (liftM) 14 | import Data.Binary (Binary, get, put) 15 | import qualified Data.ByteString as BS 16 | import qualified Data.ByteString.Builder as B 17 | import qualified Data.ByteString.UTF8 as BS_UTF8 18 | import qualified Data.Map as Map 19 | import qualified Data.Name as Name 20 | 21 | 22 | 23 | -- SOURCE 24 | 25 | 26 | newtype Source = 27 | Source BS.ByteString 28 | 29 | 30 | 31 | -- TYPES 32 | 33 | 34 | data Types = 35 | Types 36 | { _attribute :: Map.Map Name.Name Type 37 | , _uniform :: Map.Map Name.Name Type 38 | , _varying :: Map.Map Name.Name Type 39 | } 40 | 41 | 42 | data Type 43 | = Int 44 | | Float 45 | | V2 46 | | V3 47 | | V4 48 | | M4 49 | | Texture 50 | 51 | 52 | 53 | -- TO BUILDER 54 | 55 | 56 | toJsStringBuilder :: Source -> B.Builder 57 | toJsStringBuilder (Source src) = 58 | B.byteString src 59 | 60 | 61 | 62 | -- FROM CHARS 63 | 64 | 65 | fromChars :: [Char] -> Source 66 | fromChars chars = 67 | Source (BS_UTF8.fromString (escape chars)) 68 | 69 | 70 | escape :: [Char] -> [Char] 71 | escape chars = 72 | case chars of 73 | [] -> 74 | [] 75 | 76 | c:cs 77 | | c == '\r' -> escape cs 78 | | c == '\n' -> '\\' : 'n' : escape cs 79 | | c == '\"' -> '\\' : '"' : escape cs 80 | | c == '\'' -> '\\' : '\'' : escape cs 81 | | c == '\\' -> '\\' : '\\' : escape cs 82 | | otherwise -> c : escape cs 83 | 84 | 85 | 86 | -- BINARY 87 | 88 | 89 | instance Binary Source where 90 | get = liftM Source get 91 | put (Source a) = put a 92 | -------------------------------------------------------------------------------- /compiler/src/Data/Map/Utils.hs: -------------------------------------------------------------------------------- 1 | module Data.Map.Utils 2 | ( fromKeys 3 | , fromKeysA 4 | , fromValues 5 | , any 6 | ) 7 | where 8 | 9 | 10 | import Prelude hiding (any) 11 | import qualified Data.Map as Map 12 | import Data.Map.Internal (Map(..)) 13 | 14 | 15 | 16 | -- FROM KEYS 17 | 18 | 19 | fromKeys :: (Ord k) => (k -> v) -> [k] -> Map.Map k v 20 | fromKeys toValue keys = 21 | Map.fromList $ map (\k -> (k, toValue k)) keys 22 | 23 | 24 | fromKeysA :: (Applicative f, Ord k) => (k -> f v) -> [k] -> f (Map.Map k v) 25 | fromKeysA toValue keys = 26 | Map.fromList <$> traverse (\k -> (,) k <$> toValue k) keys 27 | 28 | 29 | fromValues :: (Ord k) => (v -> k) -> [v] -> Map.Map k v 30 | fromValues toKey values = 31 | Map.fromList $ map (\v -> (toKey v, v)) values 32 | 33 | 34 | 35 | -- ANY 36 | 37 | 38 | {-# INLINE any #-} 39 | any :: (v -> Bool) -> Map.Map k v -> Bool 40 | any isGood = go 41 | where 42 | go Tip = False 43 | go (Bin _ _ v l r) = isGood v || go l || go r 44 | -------------------------------------------------------------------------------- /compiler/src/Data/NonEmptyList.hs: -------------------------------------------------------------------------------- 1 | module Data.NonEmptyList 2 | ( List(..) 3 | , singleton 4 | , toList 5 | , sortBy 6 | ) 7 | where 8 | 9 | 10 | import Control.Monad (liftM2) 11 | import Data.Binary (Binary, get, put) 12 | import qualified Data.List as List 13 | 14 | 15 | 16 | -- LIST 17 | 18 | 19 | data List a = 20 | List a [a] 21 | 22 | 23 | singleton :: a -> List a 24 | singleton a = 25 | List a [] 26 | 27 | 28 | toList :: List a -> [a] 29 | toList (List x xs) = 30 | x:xs 31 | 32 | 33 | 34 | -- INSTANCES 35 | 36 | 37 | instance Functor List where 38 | fmap func (List x xs) = List (func x) (map func xs) 39 | 40 | 41 | instance Traversable List where 42 | traverse func (List x xs) = List <$> func x <*> traverse func xs 43 | 44 | 45 | instance Foldable List where 46 | foldr step state (List x xs) = step x (foldr step state xs) 47 | foldl step state (List x xs) = foldl step (step state x) xs 48 | foldl1 step (List x xs) = foldl step x xs 49 | 50 | 51 | 52 | -- SORT BY 53 | 54 | 55 | sortBy :: (Ord b) => (a -> b) -> List a -> List a 56 | sortBy toRank (List x xs) = 57 | let 58 | comparison a b = 59 | compare (toRank a) (toRank b) 60 | in 61 | case List.sortBy comparison xs of 62 | [] -> 63 | List x [] 64 | 65 | y:ys -> 66 | case comparison x y of 67 | LT -> List x (y:ys) 68 | EQ -> List x (y:ys) 69 | GT -> List y (List.insertBy comparison x ys) 70 | 71 | 72 | 73 | -- BINARY 74 | 75 | 76 | instance (Binary a) => Binary (List a) where 77 | put (List x xs) = put x >> put xs 78 | get = liftM2 List get get 79 | -------------------------------------------------------------------------------- /compiler/src/Elm/Float.hs: -------------------------------------------------------------------------------- 1 | {-# OPTIONS_GHC -Wall #-} 2 | {-# LANGUAGE EmptyDataDecls, FlexibleInstances #-} 3 | module Elm.Float 4 | ( Float 5 | , fromPtr 6 | , toBuilder 7 | ) 8 | where 9 | 10 | 11 | import Prelude hiding (Float) 12 | import Data.Binary (Binary, get, put) 13 | import qualified Data.ByteString.Builder as B 14 | import qualified Data.Utf8 as Utf8 15 | import Data.Word (Word8) 16 | import Foreign.Ptr (Ptr) 17 | 18 | 19 | 20 | -- FLOATS 21 | 22 | 23 | type Float = 24 | Utf8.Utf8 ELM_FLOAT 25 | 26 | 27 | data ELM_FLOAT 28 | 29 | 30 | 31 | -- HELPERS 32 | 33 | 34 | fromPtr :: Ptr Word8 -> Ptr Word8 -> Float 35 | fromPtr = 36 | Utf8.fromPtr 37 | 38 | 39 | {-# INLINE toBuilder #-} 40 | toBuilder :: Float -> B.Builder 41 | toBuilder = 42 | Utf8.toBuilder 43 | 44 | 45 | 46 | -- BINARY 47 | 48 | 49 | instance Binary (Utf8.Utf8 ELM_FLOAT) where 50 | get = Utf8.getUnder256 51 | put = Utf8.putUnder256 52 | -------------------------------------------------------------------------------- /compiler/src/Elm/Magnitude.hs: -------------------------------------------------------------------------------- 1 | module Elm.Magnitude 2 | ( Magnitude(..) 3 | , toChars 4 | ) 5 | where 6 | 7 | 8 | 9 | -- MAGNITUDE 10 | 11 | 12 | data Magnitude 13 | = PATCH 14 | | MINOR 15 | | MAJOR 16 | deriving (Eq, Ord) 17 | 18 | 19 | toChars :: Magnitude -> String 20 | toChars magnitude = 21 | case magnitude of 22 | PATCH -> "PATCH" 23 | MINOR -> "MINOR" 24 | MAJOR -> "MAJOR" 25 | -------------------------------------------------------------------------------- /compiler/src/Generate/Html.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | {-# LANGUAGE QuasiQuotes #-} 3 | module Generate.Html 4 | ( sandwich 5 | ) 6 | where 7 | 8 | 9 | import qualified Data.ByteString.Builder as B 10 | import Data.Monoid ((<>)) 11 | import qualified Data.Name as Name 12 | import Text.RawString.QQ (r) 13 | 14 | 15 | 16 | -- SANDWICH 17 | 18 | 19 | sandwich :: Name.Name -> B.Builder -> B.Builder 20 | sandwich moduleName javascript = 21 | let name = Name.toBuilder moduleName in 22 | [r| 23 | 24 | 25 | 26 | |] <> name <> [r| 27 | 28 | 29 | 30 | 31 | 32 |

33 | 
34 | 
52 | 
53 | 
54 | |]
55 | 


--------------------------------------------------------------------------------
/compiler/src/Generate/Mode.hs:
--------------------------------------------------------------------------------
 1 | module Generate.Mode
 2 |   ( Mode(..)
 3 |   , isDebug
 4 |   , ShortFieldNames
 5 |   , shortenFieldNames
 6 |   )
 7 |   where
 8 | 
 9 | 
10 | import qualified Data.List as List
11 | import qualified Data.Map as Map
12 | import qualified Data.Maybe as Maybe
13 | import qualified Data.Name as Name
14 | 
15 | import qualified AST.Optimized as Opt
16 | import qualified Elm.Compiler.Type.Extract as Extract
17 | import qualified Generate.JavaScript.Name as JsName
18 | 
19 | 
20 | 
21 | -- MODE
22 | 
23 | 
24 | data Mode
25 |   = Dev (Maybe Extract.Types)
26 |   | Prod ShortFieldNames
27 | 
28 | 
29 | isDebug :: Mode -> Bool
30 | isDebug mode =
31 |   case mode of
32 |     Dev mi -> Maybe.isJust mi
33 |     Prod _ -> False
34 | 
35 | 
36 | 
37 | -- SHORTEN FIELD NAMES
38 | 
39 | 
40 | type ShortFieldNames =
41 |   Map.Map Name.Name JsName.Name
42 | 
43 | 
44 | shortenFieldNames :: Opt.GlobalGraph -> ShortFieldNames
45 | shortenFieldNames (Opt.GlobalGraph _ frequencies) =
46 |   Map.foldr addToShortNames Map.empty $
47 |     Map.foldrWithKey addToBuckets Map.empty frequencies
48 | 
49 | 
50 | addToBuckets :: Name.Name -> Int -> Map.Map Int [Name.Name] -> Map.Map Int [Name.Name]
51 | addToBuckets field frequency buckets =
52 |   Map.insertWith (++) frequency [field] buckets
53 | 
54 | 
55 | addToShortNames :: [Name.Name] -> ShortFieldNames -> ShortFieldNames
56 | addToShortNames fields shortNames =
57 |   List.foldl' addField shortNames fields
58 | 
59 | 
60 | addField :: ShortFieldNames -> Name.Name -> ShortFieldNames
61 | addField shortNames field =
62 |   let rename = JsName.fromInt (Map.size shortNames) in
63 |   Map.insert field rename shortNames
64 | 


--------------------------------------------------------------------------------
/compiler/src/Reporting/Report.hs:
--------------------------------------------------------------------------------
 1 | {-# LANGUAGE OverloadedStrings #-}
 2 | module Reporting.Report
 3 |     ( Report(..)
 4 |     )
 5 |     where
 6 | 
 7 | 
 8 | import qualified Reporting.Annotation as A
 9 | import qualified Reporting.Doc as D
10 | 
11 | 
12 | 
13 | -- BUILD REPORTS
14 | 
15 | 
16 | data Report =
17 |   Report
18 |     { _title :: String
19 |     , _region :: A.Region
20 |     , _sgstns :: [String]
21 |     , _message :: D.Doc
22 |     }
23 | 


--------------------------------------------------------------------------------
/compiler/src/Reporting/Suggest.hs:
--------------------------------------------------------------------------------
 1 | {-# OPTIONS_GHC -Wall #-}
 2 | {-# LANGUAGE OverloadedStrings #-}
 3 | module Reporting.Suggest
 4 |   ( distance
 5 |   , sort
 6 |   , rank
 7 |   )
 8 |   where
 9 | 
10 | 
11 | import qualified Data.Char as Char
12 | import qualified Data.List as List
13 | import qualified Text.EditDistance as Dist
14 | 
15 | 
16 | 
17 | -- DISTANCE
18 | 
19 | 
20 | distance :: String -> String -> Int
21 | distance x y =
22 |   Dist.restrictedDamerauLevenshteinDistance Dist.defaultEditCosts x y
23 | 
24 | 
25 | 
26 | -- SORT
27 | 
28 | 
29 | sort :: String -> (a -> String) -> [a] -> [a]
30 | sort target toString values =
31 |   List.sortOn (distance (toLower target) . toLower . toString) values
32 | 
33 | 
34 | toLower :: String -> String
35 | toLower string =
36 |   map Char.toLower string
37 | 
38 | 
39 | 
40 | -- RANK
41 | 
42 | 
43 | rank :: String -> (a -> String) -> [a] -> [(Int,a)]
44 | rank target toString values =
45 |   let
46 |     toRank v =
47 |       distance (toLower target) (toLower (toString v))
48 | 
49 |     addRank v =
50 |       (toRank v, v)
51 |   in
52 |   List.sortOn fst (map addRank values)
53 | 


--------------------------------------------------------------------------------
/distribution/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 | ghcup


--------------------------------------------------------------------------------
/distribution/build-linux-x86_64-musl.sh:
--------------------------------------------------------------------------------
 1 | #!/usr/bin/env bash
 2 | set -ex                                                   # Be verbose and exit immediately on error instead of trying to continue
 3 | 
 4 | source "common.sh"
 5 | os="linux"
 6 | arch="x86_64"
 7 | 
 8 | buildTag="$project-$version-$os-$arch"
 9 | dist=distribution/dist
10 | mkdir -p $dist
11 | bin=$dist/$buildTag
12 | scriptDir=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
13 | 
14 | cd "$scriptDir/.."                                        # Move into the project root
15 | git submodule init && git submodule update
16 | 
17 |                                                           # Build in Docker
18 | docker build --platform linux/amd64 \
19 |   -t "$buildTag:latest" \
20 |   -f distribution/docker/$arch-musl.dockerfile .
21 | 
22 | mkdir -p distribution/dist                                # Ensure the dist directory is present
23 | 
24 | 
25 | bin=distribution/dist/$buildTag                           # Copy built binary to dist
26 | docker run --rm --entrypoint cat $buildTag /$project/$project > $bin
27 | chmod a+x $bin
28 | file $bin
29 | ls -alh $bin
30 | echo "put $bin $project/$project-next-$os-$arch" | sftp -i ~/.ssh/id_ed25519 -P 22 github@apps.lamdera.com
31 | 


--------------------------------------------------------------------------------
/distribution/build-macos-arm64.sh:
--------------------------------------------------------------------------------
 1 | #!/usr/bin/env bash
 2 | set -ex                                                   # Be verbose and exit immediately on error instead of trying to continue
 3 | 
 4 | source "common.sh"
 5 | os="macos"
 6 | arch="arm64"
 7 | 
 8 | buildTag="$project-$version-$os-$arch"
 9 | dist=distribution/dist
10 | mkdir -p $dist
11 | bin=$dist/$buildTag
12 | scriptDir=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
13 | 
14 | if ! uname -a | grep "Darwin" && uname -a | grep "arm64"; then
15 |   echo "This build can only be run on an Apple M-series chipset build host."
16 |   exit 1;
17 | fi
18 | 
19 | stackVersion=2.11.1
20 | isolate=~/.ghcup/$os-$arch
21 | mkdir -p $isolate
22 | stack="$isolate/stack"
23 | 
24 |                                                           # Ensure correct arch toolchain is installed, or install it
25 |                                                           # Hopefully in future ghcup has better multi-arch support
26 | if [ ! -f "$stack" ]; then
27 |   ghcup install stack "$stackVersion" --isolate "$isolate" --force
28 | fi
29 | 
30 | cd "$scriptDir/.."                                        # Move into the project root
31 | git submodule init && git submodule update
32 | 
33 | $stack install --local-bin-path $dist
34 | 
35 | cp $dist/$project $bin                                    # Copy built binary to dist
36 | strip $bin                                                # Strip symbols to reduce binary size (90M -> 56M)
37 | file $bin
38 | ls -alh $bin
39 | echo "put $bin $project/$project-next-$os-$arch" | sftp -i ~/.ssh/id_ed25519 -P 22 github@apps.lamdera.com
40 | 


--------------------------------------------------------------------------------
/distribution/build-macos-x86_64.sh:
--------------------------------------------------------------------------------
 1 | #!/usr/bin/env bash
 2 | set -ex                                                   # Be verbose and exit immediately on error instead of trying to continue
 3 | 
 4 | source "common.sh"
 5 | os="macos"
 6 | arch="x86_64"
 7 | 
 8 | buildTag="$project-$version-$os-$arch"
 9 | dist=distribution/dist
10 | mkdir -p $dist
11 | bin=$dist/$buildTag
12 | scriptDir=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
13 | 
14 | 
15 | 
16 | 
17 | 
18 | 
19 | stackVersion=2.11.1
20 | isolate=~/.ghcup/$os-$arch
21 | mkdir -p $isolate
22 | stack="$isolate/stack"
23 | 
24 |                                                           # Ensure correct arch toolchain is installed, or install it
25 |                                                           # Hopefully in future ghcup has better multi-arch support
26 | if [ ! -f "$stack" ]; then
27 |   ghcup install stack "$stackVersion" --isolate "$isolate" --force -p x86_64-apple-darwin
28 | fi
29 | 
30 | cd "$scriptDir/.."                                        # Move into the project root
31 | git submodule init && git submodule update
32 | 
33 | $stack install --local-bin-path $dist
34 | 
35 | cp $dist/$project $bin                                    # Copy built binary to dist
36 | strip $bin                                                # Strip symbols to reduce binary size (90M -> 56M)
37 | file $bin
38 | ls -alh $bin
39 | echo "put $bin $project/$project-next-$os-$arch" | sftp -i ~/.ssh/id_ed25519 -P 22 github@apps.lamdera.com
40 | 


--------------------------------------------------------------------------------
/distribution/common.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | 
3 | export project="elm-dev"
4 | export version="1.0.0"
5 | 


--------------------------------------------------------------------------------
/example/elm.json:
--------------------------------------------------------------------------------
 1 | {
 2 |     "type": "application",
 3 |     "source-directories": [
 4 |         "src"
 5 |     ],
 6 |     "elm-version": "0.19.1",
 7 |     "dependencies": {
 8 |         "direct": {
 9 |             "elm/browser": "1.0.2",
10 |             "elm/core": "1.0.5",
11 |             "elm/html": "1.0.0",
12 |             "elm/http": "2.0.0",
13 |             "elm/json": "1.1.3",
14 |             "elm/time": "1.0.0",
15 |             "elm/url": "1.0.0",
16 |             "lamdera/codecs": "1.0.0",
17 |             "lamdera/core": "1.0.0"
18 |         },
19 |         "indirect": {
20 |             "elm/bytes": "1.0.8",
21 |             "elm/file": "1.0.5",
22 |             "elm/virtual-dom": "1.0.2"
23 |         }
24 |     },
25 |     "test-dependencies": {
26 |         "direct": {},
27 |         "indirect": {}
28 |     }
29 | }
30 | 


--------------------------------------------------------------------------------
/example/src/Test/Module.elm:
--------------------------------------------------------------------------------
 1 | module Test.Module exposing (InvalidReason(..), Reason(..), myOtherFunction)
 2 | 
 3 | import Html
 4 | import Html.Attributes as Attr
 5 | import Html.Events exposing (..)
 6 | import Json.Decode as JD exposing (string)
 7 | import Json.Encode exposing (int)
 8 | import Maybe
 9 | import Result
10 | 
11 | 
12 | type Reason
13 |     = Custom
14 |     | Equality String String
15 |     | Comparison String String
16 |       -- Expected, actual, (index of problem, expected element, actual element)
17 |     | ListDiff (List String) (List String)
18 |       {- I don't think we need to show the diff twice with + and - reversed. Just show it after the main vertical bar.
19 |          "Extra" and "missing" are relative to the actual value.
20 |       -}
21 |     | CollectionDiff
22 |         { expected : String
23 |         , actual : String
24 |         , extra : List String
25 |         , missing : List String
26 |         }
27 |     | TODO
28 |     | Invalid InvalidReason
29 | 
30 | 
31 | type InvalidReason
32 |     = EmptyList
33 |     | NonpositiveFuzzCount
34 |     | InvalidFuzzer
35 |     | BadDescription
36 |     | DuplicatedName
37 | 
38 | 
39 | myOtherFunction : String -> Html.Html msg
40 | myOtherFunction incoming =
41 |     let
42 |         carl =
43 |             5
44 |     in
45 |     Html.div
46 |         (List.map identity [ Attr.id "carl" ])
47 |         [ Html.text (incoming ++ ", the Best")
48 |         ]
49 | 


--------------------------------------------------------------------------------
/ext-common/Ext/ElmFormat.hs:
--------------------------------------------------------------------------------
 1 | {-# LANGUAGE OverloadedStrings #-}
 2 | 
 3 | module Ext.ElmFormat where
 4 | 
 5 | {- Helpers to detect and use the `elm-format` binary on the local system
 6 | -}
 7 | 
 8 | import Data.Text (Text)
 9 | import qualified Data.Text as T
10 | 
11 | import System.IO.Unsafe (unsafePerformIO)
12 | import qualified System.Process
13 | import qualified System.Directory as Dir
14 | 
15 | 
16 | format :: Text -> IO (Either Text Text)
17 | format text = do
18 |   elmFormatPath_ <- Dir.findExecutable "elm-format"
19 |   case elmFormatPath_ of
20 |     Just elmFormatPath -> do
21 |       (exit, stdout, stderr) <-
22 |         System.Process.readProcessWithExitCode elmFormatPath ["--stdin"] (T.unpack text)
23 | 
24 |       if stderr /= ""
25 |         then
26 |           pure $ Left $ T.pack stderr
27 |         else
28 |           pure $ Right $ T.pack stdout
29 | 
30 |     Nothing -> do
31 |       pure $ Left $ "No elm-format found locally, skipping."
32 | 
33 | 
34 | formatOrPassthrough :: Text -> IO Text
35 | formatOrPassthrough text = do
36 |   formatted_ <- format text
37 |   case formatted_ of
38 |     Right formatted -> pure formatted
39 |     Left err -> pure text
40 | 


--------------------------------------------------------------------------------
/ext-common/Ext/MemoryCached/BackgroundWriter.hs:
--------------------------------------------------------------------------------
 1 | -- Clone of builder/src/BackgroundWriter.hs modified to use MemoryCached.*
 2 | 
 3 | {-# LANGUAGE BangPatterns #-}
 4 | module Ext.MemoryCached.BackgroundWriter
 5 |   ( Scope
 6 |   , withScope
 7 |   , writeBinary
 8 |   )
 9 |   where
10 | 
11 | 
12 | import Control.Concurrent (forkIO)
13 | import Control.Concurrent.MVar (MVar, newEmptyMVar, newMVar, putMVar, takeMVar)
14 | import qualified Data.Binary as Binary
15 | import Data.Foldable (traverse_)
16 | 
17 | import qualified Ext.FileCache as File
18 | 
19 | import BackgroundWriter (Scope(..))
20 | 
21 | 
22 | -- BACKGROUND WRITER
23 | 
24 | 
25 | -- newtype Scope =
26 | --   Scope (MVar [MVar ()])
27 | 
28 | 
29 | withScope :: (Scope -> IO a) -> IO a
30 | withScope callback =
31 |   do  workList <- newMVar []
32 |       result <- callback (Scope workList)
33 |       mvars <- takeMVar workList
34 |       traverse_ takeMVar mvars
35 |       return result
36 | 
37 | 
38 | writeBinary :: (Binary.Binary a) => Scope -> FilePath -> a -> IO ()
39 | writeBinary (Scope workList) path value =
40 |   do  mvar <- newEmptyMVar
41 |       _ <- forkIO (File.writeBinary path value >> putMVar mvar ())
42 |       oldWork <- takeMVar workList
43 |       let !newWork = mvar:oldWork
44 |       putMVar workList newWork
45 | 
46 | 


--------------------------------------------------------------------------------
/ext-common/Ext/MemoryCached/readme.md:
--------------------------------------------------------------------------------
1 | 
2 | The contents of Ext.MemoryCached are vendored from Elm core with minor modifications
3 | 
4 | Running `vendor.sh` should cause a no-op, unless Elm core changes significantly in a future version, and in that scenario hopefully our modifications are relatively easy to setup again.
5 | 
6 | In any case – this should be less pain than having directly modified the original files to support different modes and then trying to keep up.
7 | 


--------------------------------------------------------------------------------
/ext-common/Ext/MemoryCached/vendor.sh:
--------------------------------------------------------------------------------
 1 | #!/bin/bash
 2 | 
 3 | # TBC!
 4 | 
 5 | 
 6 | icdiff builder/src/BackgroundWriter.hs ext-common/Ext/MemoryCached/BackgroundWriter.hs
 7 | icdiff builder/src/Build.hs ext-common/Ext/MemoryCached/Build.hs
 8 | icdiff builder/src/Details.hs ext-common/Ext/MemoryCached/Details.hs
 9 | icdiff builder/src/Generate.hs ext-common/Ext/MemoryCached/Generate.hs
10 | 


--------------------------------------------------------------------------------
/ext-common/readme.md:
--------------------------------------------------------------------------------
1 | 
2 | ### Elmx Common
3 | 
4 | A set of generic code/helpers.
5 | 


--------------------------------------------------------------------------------
/ext-dev/DEVELOPING.md:
--------------------------------------------------------------------------------
 1 | # Developing Elm Dev
 2 | 
 3 | These are some instructions to get things set up for development.  Just went through this on an M4 Macbook.
 4 | 
 5 | 1. Install XCode CLI tools: `xcode-select --install`
 6 | 2. Install GHCup: https://www.haskell.org/ghcup/
 7 | 3. Install homebrew: https://brew.sh/
 8 |    - Install llvm: `brew install llvm`
 9 |    - Install pkg-config: `brew install pkg-config`
10 | 
11 | Once this is done, run `stack build` in this directory.


--------------------------------------------------------------------------------
/ext-dev/ElmDevElmVersion.hs:
--------------------------------------------------------------------------------
 1 | module ElmDevElmVersion (elmVersion) where
 2 | 
 3 | 
 4 | import Data.Version (Version(..))
 5 | 
 6 | {-|
 7 | This is the version of Elm that Elm Dev is meant to work with.
 8 | 
 9 | 
10 | -}
11 | elmVersion :: Version
12 | elmVersion = Version [0,19,1] []


--------------------------------------------------------------------------------
/ext-dev/Ext/Dev/Canonicalize.hs:
--------------------------------------------------------------------------------
 1 | {-# LANGUAGE OverloadedStrings #-}
 2 | 
 3 | module Ext.Dev.Canonicalize
 4 |   ( type_
 5 |   )
 6 | where
 7 | 
 8 | import AST.Canonical (Type (..))
 9 | import qualified AST.Source as Src
10 | import qualified AST.Canonical as Can
11 | import qualified Reporting.Result
12 | import qualified Canonicalize.Environment
13 | import qualified Canonicalize.Type
14 | import qualified Ext.CompileProxy
15 | 
16 | 
17 | {-| For canonicalizing pieces of a Src module instead of the whole thing.
18 | 
19 | -}
20 | type_ :: String -> String -> Src.Module -> Src.Type -> IO (Maybe Can.Type)
21 | type_ root path srcMod tipe = do
22 |     canonicalizationEnvResult <- Ext.CompileProxy.loadCanonicalizeEnv root path srcMod
23 |     case canonicalizationEnvResult of
24 |         Nothing ->
25 |             pure Nothing
26 | 
27 |         Just env -> do
28 |             let (warnings, eitherCanType) = Reporting.Result.run $ Canonicalize.Type.canonicalize env tipe
29 | 
30 |             case eitherCanType of
31 |                 Left err ->
32 |                     pure Nothing
33 | 
34 |                 Right canType ->
35 |                     pure (Just canType)
36 | 
37 | 
38 | 
39 |              


--------------------------------------------------------------------------------
/ext-dev/Ext/Dev/Json/Encode.hs:
--------------------------------------------------------------------------------
 1 | {-# LANGUAGE OverloadedStrings #-}
 2 | 
 3 | module Ext.Dev.Json.Encode
 4 |   ( set
 5 |   , moduleName
 6 |   , region
 7 |   , Ext.Dev.Json.Encode.maybe
 8 |   )
 9 | where
10 | 
11 | import qualified Reporting.Annotation as Ann
12 | import qualified Data.Name as Name
13 | import qualified Data.Set as Set
14 | 
15 | import qualified Json.Encode
16 | import Json.Encode ((==>))
17 | 
18 | import qualified Elm.ModuleName as ModuleName
19 | import qualified Elm.Package as Package
20 | 
21 | 
22 | 
23 | {- Primitive Helpers -}
24 | 
25 | 
26 | set :: (a -> Json.Encode.Value) -> Set.Set a -> Json.Encode.Value
27 | set encodeValue set =
28 |   Json.Encode.list encodeValue (Set.toList set)
29 | 
30 | 
31 | 
32 | 
33 | moduleName :: ModuleName.Canonical -> Json.Encode.Value
34 | moduleName (ModuleName.Canonical pkgName modName) =
35 |     Json.Encode.object 
36 |         [ "pkg" ==> Package.encode pkgName
37 |         , "module" ==>  Json.Encode.chars (Name.toChars modName)
38 |         ]   
39 | 
40 | maybe :: (a -> Json.Encode.Value) -> Maybe a -> Json.Encode.Value
41 | maybe toVal possibly =
42 |   case possibly of
43 |     Nothing -> Json.Encode.null
44 |     Just a -> toVal a
45 | 
46 | region :: Ann.Region -> Json.Encode.Value
47 | region (Ann.Region start end) =
48 |     Json.Encode.object
49 |         [ ("start" ==> position start)
50 |         , ("end" ==> position end)
51 |         ]
52 | 
53 | 
54 | position :: Ann.Position -> Json.Encode.Value
55 | position (Ann.Position row col) =
56 |     Json.Encode.object
57 |         [ ("line" ==> Json.Encode.int (fromIntegral row))
58 |         , ("column" ==> Json.Encode.int (fromIntegral col))
59 |         ]


--------------------------------------------------------------------------------
/ext-dev/Ext/Dev/Search.hs:
--------------------------------------------------------------------------------
 1 | {-# LANGUAGE OverloadedStrings #-}
 2 | 
 3 | module Ext.Dev.Search
 4 |   ( search
 5 |   , SearchResult(..)
 6 |   )
 7 | where
 8 | 
 9 | 
10 | {-|
11 | 
12 | ## These modules are all very similar:
13 | 
14 | Ext.Dev.Find -> Source Position -> Definition
15 | Ext.Dev.Lookup -> Module -> Value.Name -> Definition
16 | Ext.Dev.Search -> Module -> Value.Name -> Maybe { definition : Definition, usages : [ Source Position ]}
17 | 
18 | -}
19 | 
20 | import qualified AST.Source as Src
21 | import qualified AST.Canonical as Can
22 | import qualified Reporting.Annotation as A
23 | import qualified Parse.Primitives as P
24 | import qualified Watchtower.Editor
25 | import qualified Data.List as List
26 | 
27 | import qualified Elm.ModuleName as ModuleName
28 | import qualified Elm.Details
29 | import qualified Ext.Dev.Project
30 | import qualified Ext.Dev.Lookup
31 | 
32 | import qualified Ext.CompileProxy
33 | 
34 | import Data.Name (Name)
35 | import qualified Data.Map as Map
36 | import Data.Function ((&))
37 | 
38 | data SearchResult =
39 |     SearchResult
40 |         { _definition :: Ext.Dev.Lookup.LookupResult
41 |         -- , _usages :: [Src.Position]
42 |         }
43 | 
44 | 
45 | search :: String -> ModuleName.Raw -> Name -> IO (Maybe SearchResult)
46 | search root mod valueName =
47 |     do
48 |        project <- Ext.CompileProxy.loadProject root
49 | 
50 |        importers <- Ext.Dev.Project.importersOf project mod
51 | 
52 |        found <- Ext.Dev.Lookup.lookupDefinition root mod valueName
53 |        pure (SearchResult <$> found)
54 | 
55 | 


--------------------------------------------------------------------------------
/ext-dev/Terminal/Colors.hs:
--------------------------------------------------------------------------------
 1 | module Terminal.Colors (
 2 |   yellow,
 3 |   green,
 4 |   cyan,
 5 |   grey
 6 | ) where
 7 | 
 8 | 
 9 | -- | Wrap a string in yellow color
10 | yellow :: String -> String
11 | yellow str = "\ESC[33m" ++ str ++ "\ESC[0m"
12 | 
13 | -- | Wrap a string in green color
14 | green :: String -> String
15 | green str = "\ESC[32m" ++ str ++ "\ESC[0m"
16 | 
17 | -- | Wrap a string in cyan color
18 | cyan :: String -> String
19 | cyan str = "\ESC[36m" ++ str ++ "\ESC[0m"
20 | 
21 | -- | Wrap a string in grey color
22 | grey :: String -> String
23 | grey str = "\ESC[90m" ++ str ++ "\ESC[0m" 


--------------------------------------------------------------------------------
/ext-dev/Test.hs:
--------------------------------------------------------------------------------
 1 | module Test where
 2 | 
 3 | {-
 4 | 
 5 | Setup your ~/.ghci config:
 6 | 
 7 | ```
 8 | :set -fbyte-code
 9 | :set -fobject-code
10 | :set prompt "\ESC[34mλ: \ESC[m"
11 | 
12 | :def rr const $ return $ unlines ["Ext.Common.killTrackedThreads",":r","Test.target"]
13 | ```
14 | 
15 | Then use `:rr` to kill threads, recompile and re-run Test.target.
16 | 
17 | The current working directory will be reset back to wherever `stack ghci` was
18 | first invoked, before the `:r` is handled.
19 | 
20 | Note: make sure to use `Ext.Common.trackedForkIO` instead of `Control.Concurrent.forkIO`,
21 | otherwise there's no way to find+kill all child threads in GHCI context!
22 | 
23 | -}
24 | 
25 | import Watchtower.Test
26 | 
27 | target =
28 |   Watchtower.Test.serve
29 | 


--------------------------------------------------------------------------------
/ext-dev/Util.hs:
--------------------------------------------------------------------------------
 1 | {-# LANGUAGE BangPatterns #-}
 2 | {-# LANGUAGE OverloadedStrings #-}
 3 | 
 4 | module Util
 5 |   ( encodeName,
 6 |     encodeModuleName,
 7 |     encodeModulePackage,
 8 |   )
 9 | where
10 | 
11 | import Data.Function ((&))
12 | import qualified Data.Name as Name
13 | import qualified Elm.ModuleName as ModuleName
14 | import qualified Elm.Package
15 | import Json.Encode
16 | import Json.String
17 | 
18 | encodeName :: Name.Name -> Json.Encode.Value
19 | encodeName name =
20 |   Json.String.fromChars (Name.toChars name)
21 |     & Json.Encode.string
22 | 
23 | encodeModuleName :: ModuleName.Canonical -> Json.Encode.Value
24 | encodeModuleName can =
25 |   can
26 |     & ModuleName._module
27 |     & encodeName
28 | 
29 | encodeModulePackage :: ModuleName.Canonical -> Json.Encode.Value
30 | encodeModulePackage can =
31 |   can
32 |     & ModuleName._package
33 |     & Elm.Package.toJsonString
34 |     & Json.Encode.string
35 | 


--------------------------------------------------------------------------------
/ext-dev/readme.md:
--------------------------------------------------------------------------------
 1 | # elm-dev
 2 | 
 3 | This is both an elm compiler extension + server, as well as an app that talks to that server.
 4 | 
 5 | ## Gettings Started
 6 | 
 7 | 1. Put the following into `~/.ghci`
 8 | 
 9 | ```
10 | :set -fbyte-code
11 | :set -fobject-code
12 | :set prompt "\ESC[34mλ: \ESC[m"
13 | :def rr const $ return $ unlines ["Ext.Common.killTrackedThreads",":r","Test.target"]
14 | ```
15 | 
16 | 2. Run `stack ghci`
17 | 
18 | 3. Run `:set -XOverloadedStrings`
19 | 
20 | 4. Run `Test.target` - Seems weird, but this starts the elm-dev server!
21 | 
22 | 5. Then the dev feedback loop goes as follows:
23 | 
24 | - Make changes to Haskell code
25 | - Run `:rr` to kill all threads, typecheck + recompile, and re-run `Test.target`
26 | - Fix any issues, then `:rr` again
27 | - If you want to just type-check _without_ running, use `:r`
28 | 
29 | Easier to change the target definition than constantly adjust the `:def` in `~/.ghci`!
30 | 
31 | Check out `WatchTower.Test` to see the cli args provided for development.
32 | 
33 | ## What the server does
34 | 
35 | When the server starts, then `Ext.Dev.Project.discover` will run in the current directory.
36 | 
37 | This recursively searches for `elm.json` files and notes them.
38 | 
39 | At the moment, it also looks for `src/Main.elm` as the entrypoint, though there are still questions about what to do about files that aren't imported by the entrypoint.
40 | 
41 | ## Install Watchtower locally
42 | 
43 | Run `stack install` and it will compile and copy the `elm-dev` binaries to your PATH.
44 | 


--------------------------------------------------------------------------------
/ext-generate/DEVELOPING.md:
--------------------------------------------------------------------------------
1 | # Commands
2 | 
3 | 
4 | ```
5 | stack run --cwd playground -- init
6 | stack run --cwd playground -- make
7 | ```


--------------------------------------------------------------------------------
/ext-generate/Gen/Javascript.hs:
--------------------------------------------------------------------------------
 1 | {-# OPTIONS_GHC -Wall #-}
 2 | {-# LANGUAGE OverloadedStrings #-}
 3 | {-# LANGUAGE TemplateHaskell #-}
 4 | module Gen.Javascript where
 5 | 
 6 | import qualified Language.Haskell.TH
 7 | import qualified Data.FileEmbed
 8 | import System.Process (readCreateProcess, shell, StdStream(..), withCreateProcess, waitForProcess, std_in, std_out)
 9 | import Control.Exception (try, SomeException)
10 | import qualified Data.ByteString as BS
11 | import qualified Data.ByteString.UTF8 as UTF8
12 | import System.IO.Temp (withSystemTempFile)
13 | import System.FilePath (())
14 | import System.Exit (ExitCode(..))
15 | import System.IO (hClose, hGetContents)
16 | 
17 | -- | Load a file at compile time
18 | generatorJs :: BS.ByteString
19 | generatorJs =
20 |      $(Data.FileEmbed.bsToExp =<< 
21 |         Language.Haskell.TH.runIO 
22 |             (BS.readFile ("ext-generate"  "generator"  "dist"  "run.js"))
23 |      )
24 | 
25 | 
26 | -- | Execute embedded JavaScript using Bun
27 | run :: BS.ByteString -> BS.ByteString ->  IO (Either String String)
28 | run jsCode input = withSystemTempFile "embedded.js" $ \tempPath handle -> do
29 |     -- Write the embedded code to a temporary file
30 |     BS.hPut handle jsCode
31 |     hClose handle  -- Close the handle after writing
32 |     -- Execute using Bun and pass input through stdin
33 |     let process = shell $ "node " ++ tempPath
34 |     result <- try $ readCreateProcess process (UTF8.toString input)
35 |     case result of
36 |         Left err -> return $ Left $ "Error executing script: " ++ show (err :: SomeException)
37 |         Right output -> return $ Right output
38 | 
39 | 
40 | -- Dynamically adjusted by build.sh to make sure haskell doesn't bamboozle us.
41 | version :: String
42 | version = "c4e6cfb356d5239f"
43 | 


--------------------------------------------------------------------------------
/ext-generate/Modify.hs:
--------------------------------------------------------------------------------
 1 | {-# LANGUAGE ScopedTypeVariables #-}
 2 | 
 3 | module Modify (update, Modifications(..)) where
 4 | 
 5 | import qualified Elm.ModuleName as Module
 6 | import qualified AST.Canonical as Can
 7 | import qualified Modify.Ui
 8 | 
 9 | data Modifications =
10 |   Modifications
11 |     { uiSourceMap :: Bool
12 |     }
13 | 
14 | {-|
15 | 
16 | Do any AST modifications we want for elm-dev
17 | 
18 | 
19 | -}
20 | update :: Modifications -> Can.Module -> Can.Module
21 | update modifications canonical =
22 |   if uiSourceMap modifications then
23 |     let
24 |       moduleName :: Module.Canonical = (Can._name canonical)
25 |       decls :: Can.Decls = (Can._decls canonical)
26 |       newDecls :: Can.Decls =  Modify.Ui.updateDecls moduleName decls
27 |     in
28 |     canonical { Can._decls = newDecls }
29 |   else
30 |     canonical
31 | 


--------------------------------------------------------------------------------
/ext-generate/README.md:
--------------------------------------------------------------------------------
 1 | # The Generation Extension
 2 | 
 3 | Welcome to Elm Dev
 4 | 
 5 |   elm-prefab ${Chalk.green("init")} ................ create a new project
 6 |   elm-prefab ${Chalk.green("generate")}.................... generate code
 7 | 
 8 |  Add to your Elm app:
 9 | 
10 |   elm-prefab ${Chalk.green("add")} ${Chalk.grey("(interactive)")}
11 |   elm-prefab ${Chalk.green("add page ")} ............ add a new page
12 |   elm-prefab ${Chalk.green("add store ")} ... add a new store
13 |   elm-prefab ${Chalk.green("add effect ")} ....... add a new effect
14 |   elm-prefab ${Chalk.green("add docs")} ................. add a docs site
15 |   elm-prefab ${Chalk.green("add graphql")} .................. add GraphQL
16 |   elm-prefab ${Chalk.green("add theme")} .................... add a theme
17 | 
18 |  Move an elm-prefab-controlled file into your project.
19 | 
20 |   elm-prefab ${Chalk.green("customize")} ${Chalk.grey("(interactive)")}
21 |   elm-prefab ${Chalk.green("customize ")}


--------------------------------------------------------------------------------
/ext-generate/generator/.gitignore:
--------------------------------------------------------------------------------
1 | codegen/Gen
2 | bun.lockb


--------------------------------------------------------------------------------
/ext-generate/generator/README.md:
--------------------------------------------------------------------------------
 1 | # generator
 2 | 
 3 | To install dependencies:
 4 | 
 5 | ```bash
 6 | bun install
 7 | ```
 8 | 
 9 | To run:
10 | 
11 | ```bash
12 | bun run index.ts
13 | ```
14 | 
15 | This project was created using `bun init` in bun v1.1.43. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.
16 | 


--------------------------------------------------------------------------------
/ext-generate/generator/app/templates/customizable/App/Page/Error.elm:
--------------------------------------------------------------------------------
 1 | module App.Page.Error exposing (Error(..))
 2 | 
 3 | {-| You may want to protect a page with a certain error when it is first requested.
 4 | 
 5 |   - `NotFound` is built in to `elm-prefab`, so you don't need to capture that here.
 6 | 
 7 | Common errors are
 8 | 
 9 |     - Unauthenticated — When you require someone to be signed in in order to see a page.
10 |     - Permission denied — When you require taht someone is both signed in and has certain permissions.
11 | 
12 | @docs Error
13 | 
14 | -}
15 | 
16 | 
17 | type Error
18 |     = Unauthenticated
19 | 


--------------------------------------------------------------------------------
/ext-generate/generator/app/templates/customizable/App/View.elm:
--------------------------------------------------------------------------------
 1 | module App.View exposing (View, map)
 2 | 
 3 | {-|
 4 | 
 5 | @docs View, map
 6 | 
 7 | -}
 8 | 
 9 | import Html
10 | 
11 | 
12 | type alias View msg =
13 |     { title : String
14 |     , body : Html.Html msg
15 |     }
16 | 
17 | 
18 | map : (a -> b) -> View a -> View b
19 | map fn myView =
20 |     { title = myView.title
21 |     , body = Html.map fn myView.body
22 |     }
23 | 


--------------------------------------------------------------------------------
/ext-generate/generator/app/templates/customizable/Broadcast.elm:
--------------------------------------------------------------------------------
 1 | module Broadcast exposing (Msg(..))
 2 | 
 3 | {-| This is a module that is special for elm-prefab.
 4 | 
 5 | The `Msg` here can be broadcasted globally to any page that is listening.
 6 | 
 7 | To broadcast a message, you'd do this in your `update` function:
 8 | 
 9 |     Effect.broadcast Broadcast.LogOut
10 | 
11 | And to listen for this message, in your subscriptions, you'd have
12 | 
13 |     Listen.onBroadcast
14 |         (\broadcastMsg ->
15 |             case broadcastMsg of
16 |                 Broadcast.LogOut ->
17 |                     -- You can choose which messages you opt in to.
18 |                     Nothing
19 |         )
20 | 
21 | @docs Msg
22 | 
23 | -}
24 | 
25 | 
26 | type Msg
27 |     = LogOut
28 | 


--------------------------------------------------------------------------------
/ext-generate/generator/app/templates/customizable/Effect/Clipboard.elm:
--------------------------------------------------------------------------------
 1 | port module Effect.Clipboard exposing (copy)
 2 | 
 3 | {-| Copy a value to the clipboard
 4 | 
 5 | @docs copy
 6 | 
 7 | -}
 8 | 
 9 | import Effect
10 | import Json.Encode as Json
11 | 
12 | 
13 | port clipboard : Json.Value -> Cmd msg
14 | 
15 | 
16 | copy : String -> Effect.Effect msg
17 | copy text =
18 |     Effect.SendToWorld
19 |         { toPort = clipboard
20 |         , portName = "clipboard"
21 |         , payload =
22 |             Json.string text
23 |         }
24 | 


--------------------------------------------------------------------------------
/ext-generate/generator/app/templates/customizable/Effect/File.elm:
--------------------------------------------------------------------------------
 1 | module Effect.File exposing (selectFile, selectMultipleFiles, toUrl)
 2 | 
 3 | {-|
 4 | 
 5 | @docs selectFile, selectMultipleFiles, toUrl
 6 | 
 7 | -}
 8 | 
 9 | import Effect
10 | import File
11 | 
12 | 
13 | {-| -}
14 | selectFile : List String -> (File.File -> msg) -> Effect.Effect msg
15 | selectFile =
16 |     Effect.File
17 | 
18 | 
19 | selectMultipleFiles : List String -> (File.File -> List File.File -> msg) -> Effect.Effect msg
20 | selectMultipleFiles =
21 |     Effect.Files
22 | 
23 | 
24 | toUrl : File.File -> (String -> msg) -> Effect.Effect msg
25 | toUrl fileData toMsg =
26 |     Effect.FileToUrl fileData toMsg
27 | 


--------------------------------------------------------------------------------
/ext-generate/generator/app/templates/customizable/Effect/Focus.elm:
--------------------------------------------------------------------------------
 1 | port module Effect.Focus exposing (focus, blur, select)
 2 | 
 3 | {-| Focus a text input and select the text.
 4 | 
 5 | @docs focus, blur, select
 6 | 
 7 | -}
 8 | 
 9 | import Browser.Dom
10 | import Effect
11 | import Json.Encode as Json
12 | 
13 | 
14 | {-| Attempt to change the browser focus to the element with a given id.
15 | -}
16 | focus : String -> (Result Browser.Dom.Error () -> msg) -> Effect.Effect msg
17 | focus =
18 |     Effect.Focus
19 | 
20 | 
21 | {-| Make a specific element lose focus.
22 | -}
23 | blur : String -> (Result Browser.Dom.Error () -> msg) -> Effect.Effect msg
24 | blur =
25 |     Effect.Blur
26 | 
27 | 
28 | port textSelection : Json.Value -> Cmd msg
29 | 
30 | 
31 | {-| Give the id of the text element you want to focus and select the contents of.
32 | -}
33 | select : String -> Effect.Effect msg
34 | select id =
35 |     Effect.SendToWorld
36 |         { toPort = textSelection
37 |         , portName = "textSelection"
38 |         , payload =
39 |             Json.object [ ( "id", Json.string id ) ]
40 |         }
41 | 


--------------------------------------------------------------------------------
/ext-generate/generator/app/templates/customizable/Effect/LocalStorage.elm:
--------------------------------------------------------------------------------
 1 | port module Effect.LocalStorage exposing (clear, save)
 2 | 
 3 | {-|
 4 | 
 5 | @docs clear, save
 6 | 
 7 | -}
 8 | 
 9 | import Effect
10 | import Json.Encode as Json
11 | 
12 | 
13 | port localStorage : Json.Value -> Cmd msg
14 | 
15 | 
16 | {-| -}
17 | save : String -> Json.Value -> Effect.Effect msg
18 | save key value =
19 |     send "save"
20 |         (Json.object
21 |             [ ( "key", Json.string key )
22 |             , ( "value", value )
23 |             ]
24 |         )
25 | 
26 | 
27 | {-| -}
28 | clear : String -> Effect.Effect msg
29 | clear key =
30 |     send "clear"
31 |         (Json.object
32 |             [ ( "key", Json.string key )
33 |             ]
34 |         )
35 | 
36 | 
37 | send : String -> Json.Value -> Effect.Effect msg
38 | send operation value =
39 |     Effect.SendToWorld
40 |         { toPort = localStorage
41 |         , portName = "local-storage"
42 |         , payload =
43 |             Json.object
44 |                 [ ( "operation", Json.string operation )
45 |                 , ( "details", value )
46 |                 ]
47 |         }
48 | 


--------------------------------------------------------------------------------
/ext-generate/generator/app/templates/customizable/Effect/Page.elm:
--------------------------------------------------------------------------------
 1 | module Effect.Page exposing
 2 |     ( preload
 3 |     , loadAt, clear
 4 |     )
 5 | 
 6 | {-|
 7 | 
 8 | @docs preload
 9 | 
10 | @docs loadAt, clear
11 | 
12 | -}
13 | 
14 | import App.Page.Id
15 | import App.View.Region
16 | import Effect exposing (Effect)
17 | 
18 | 
19 | {-| Load the data for a page, but don't show it yet.
20 | -}
21 | preload : App.Page.Id.Id -> Effect msg
22 | preload =
23 |     Effect.Preload
24 | 
25 | 
26 | {-| Load the page (if necessary) and view a page at a specific region
27 | -}
28 | loadAt : App.View.Region.Region -> App.Page.Id.Id -> Effect msg
29 | loadAt region pageId =
30 |     Effect.ViewUpdated (App.View.Region.Push region pageId)
31 | 
32 | 
33 | {-| -}
34 | clear : App.View.Region.Region -> Effect msg
35 | clear region =
36 |     Effect.ViewUpdated (App.View.Region.ClearRegion region)
37 | 


--------------------------------------------------------------------------------
/ext-generate/generator/app/templates/customizable/Effect/Random.elm:
--------------------------------------------------------------------------------
 1 | module Effect.Random exposing (generate)
 2 | 
 3 | {-|
 4 | 
 5 | @docs generate
 6 | 
 7 | -}
 8 | 
 9 | import Effect
10 | import Random
11 | 
12 | 
13 | {-| Run a random generator to produce a value.
14 | -}
15 | generate : (item -> msg) -> Random.Generator item -> Effect.Effect msg
16 | generate fn generator =
17 |     Effect.Generate (Random.map fn generator)
18 | 


--------------------------------------------------------------------------------
/ext-generate/generator/app/templates/customizable/Effect/Scroll.elm:
--------------------------------------------------------------------------------
 1 | port module Effect.Scroll exposing
 2 |     ( toTop, toBottom, to
 3 |     , resetWindow
 4 |     )
 5 | 
 6 | {-|
 7 | 
 8 | @docs toTop, toBottom, to
 9 | 
10 | @docs resetWindow
11 | 
12 | -}
13 | 
14 | import Browser.Dom
15 | import Effect exposing (Effect)
16 | import Json.Encode as Json
17 | 
18 | 
19 | {-| -}
20 | toTop : { id : String, onScrollFinish : msg } -> Effect msg
21 | toTop =
22 |     Effect.ScrollToTopOf
23 | 
24 | 
25 | {-| -}
26 | toBottom : { id : String, onScrollFinish : msg } -> Effect msg
27 | toBottom =
28 |     Effect.ScrollToBottomOf
29 | 
30 | 
31 | {-| -}
32 | to :
33 |     { scrollTo : String
34 |     , viewport : String
35 |     , offsetY : Float
36 |     , onScrollFinish : Result Browser.Dom.Error () -> msg
37 |     }
38 |     -> Effect msg
39 | to =
40 |     Effect.ScrollTo
41 | 
42 | 
43 | port resetWindowScroll : Json.Value -> Cmd msg
44 | 
45 | 
46 | {-| -}
47 | resetWindow : Effect msg
48 | resetWindow =
49 |     Effect.SendToWorld
50 |         { toPort = resetWindowScroll
51 |         , portName = "resetWindowScroll"
52 |         , payload =
53 |             Json.bool True
54 |         }
55 | 


--------------------------------------------------------------------------------
/ext-generate/generator/app/templates/customizable/Listen/LocalStorage.elm:
--------------------------------------------------------------------------------
 1 | port module Listen.LocalStorage exposing (onUpdated)
 2 | 
 3 | {-|
 4 | 
 5 | @docs onUpdated
 6 | 
 7 | -}
 8 | 
 9 | import Json.Decode
10 | import Json.Encode
11 | import Listen
12 | import Platform.Sub
13 | 
14 | 
15 | port localStorageUpdated : (Json.Encode.Value -> msg) -> Platform.Sub.Sub msg
16 | 
17 | 
18 | onUpdated :
19 |     { key : String
20 |     , decoder : Json.Decode.Decoder msg
21 |     }
22 |     -> Listen.Listen msg
23 | onUpdated options =
24 |     Listen.OnFromJs
25 |         { portName = "localStorageUpdated"
26 |         , subscription =
27 |             localStorageUpdated
28 |                 (Json.Decode.decodeValue options.decoder)
29 |         }
30 | 


--------------------------------------------------------------------------------
/ext-generate/generator/app/templates/oneOff/Effect.elm:
--------------------------------------------------------------------------------
 1 | port module Effect.{{name}} exposing (send)
 2 | 
 3 | {-| -}
 4 | 
 5 | import Effect
 6 | import Json.Encode as Json
 7 | 
 8 | 
 9 | port {{name_decapitalized}} : Json.Value -> Cmd msg
10 | 
11 | 
12 | send : String -> Json.Value -> Effect.Effect msg
13 | send operation value =
14 |     Effect.SendToWorld
15 |         { toPort = {{name_decapitalized}}
16 |         , portName = "{{name}}"
17 |         , payload =
18 |             Json.object
19 |                 [ ( "operation", Json.string operation )
20 |                 , ( "details", value )
21 |                 ]
22 |         }
23 | 


--------------------------------------------------------------------------------
/ext-generate/generator/app/templates/oneOff/Listen.elm:
--------------------------------------------------------------------------------
 1 | port module Listen.{{name}} exposing (..)
 2 | 
 3 | {-| Listen for messages from JS.
 4 | 
 5 | Once you've added this module to your app, you can send messages to your Elm App by
 6 | adding something like the following to your main.ts
 7 | 
 8 | 
 9 |     // Connect to a WebSocket
10 |     const socket = new WebSocket("ws://localhost:8080");
11 |     // When a message comes into our WebSocket, we pass the message along
12 |     // to the {{name_decapitalized}} port.
13 |     socket.addEventListener("message", function(event) {
14 |         app.ports.{{name_decapitalized}}.send(event.data);
15 |     });
16 | 
17 | 
18 | -}
19 | 
20 | import Json.Decode
21 | import Platform.Sub
22 | import Listen
23 | 
24 | 
25 | port {{name_decapitalized}} : (Json.Decode.Value -> msg) -> Platform.Sub.Sub msg
26 | 
27 | 
28 | listen : Json.Decode.Decoder msg -> Listen.Listen msg
29 | listen options =
30 |     Listen.OnFromJs
31 |         { portName = "{{name_decapitalized}}"
32 |         , subscription =
33 |             {{name_decapitalized}}
34 |                 (Json.Decode.decodeValue options.decoder)
35 |         }
36 | 


--------------------------------------------------------------------------------
/ext-generate/generator/app/templates/oneOff/Page.elm:
--------------------------------------------------------------------------------
 1 | module Page.{{name}} exposing
 2 |     ( page
 3 |     , Model, Msg
 4 |     )
 5 | 
 6 | {-|
 7 | 
 8 | @docs page
 9 | @docs Model, Msg
10 | 
11 | -}
12 | 
13 | import Effect
14 | import App.Page
15 | import App.Page.Id
16 | import App.Stores
17 | import Listen
18 | import App.View
19 | import App.View.Region
20 | import Html
21 | 
22 | 
23 | {-| -}
24 | type alias Model =
25 |     {}
26 | 
27 | 
28 | {-| -}
29 | type Msg
30 |     = ReplaceMe
31 | 
32 | 
33 | page : App.Page.Page App.Stores.Stores App.Page.Id.{{name_underscored}}_Params Msg Model
34 | page =
35 |     App.Page.page
36 |         { init = init
37 |         , update = update
38 |         , subscriptions = \stores model -> Listen.none
39 |         , view = view
40 |         }
41 | 
42 | 
43 | init : App.Page.Id.Id -> App.Page.Id.{{name_underscored}}_Params -> App.Stores.Stores -> Maybe Model -> App.Page.Init Msg Model
44 | init pageId urlParams stores maybeCached =
45 |     App.Page.init {}
46 | 
47 | 
48 | update : App.Stores.Stores -> Msg -> Model -> ( Model, Effect.Effect Msg )
49 | update stores msg model =
50 |     ( model, Effect.none )
51 | 
52 | 
53 | view : App.View.Region.Id -> App.Stores.Stores -> Model -> App.View.View Msg
54 | view viewId stores model =
55 |    { title = "{{name}}"
56 |    , body = Html.text "{{name}}"
57 |    }
58 | 


--------------------------------------------------------------------------------
/ext-generate/generator/app/templates/oneOff/Store.elm:
--------------------------------------------------------------------------------
 1 | module Store.{{name}} exposing
 2 |     ( store
 3 |     , Model, Msg(..)
 4 |     )
 5 | 
 6 | {-|
 7 | 
 8 | @docs store
 9 | 
10 | @docs Model, Msg
11 | 
12 | -}
13 | 
14 | import App.Store
15 | import Effect
16 | import Json.Decode
17 | import Json.Encode
18 | import Listen
19 | 
20 | 
21 | type alias Model =
22 |     {}
23 | 
24 | 
25 | type Msg
26 |     = ReplaceMe
27 | 
28 | 
29 | store : App.Store.Store Msg Model
30 | store =
31 |     App.Store.store
32 |         { init =
33 |             \flags url maybeCachedModel ->
34 |                 let
35 |                     model =
36 |                         -- `maybeCachedModel` is the model from localstorage
37 |                         -- If `App.Store.withLocalStorage` is defined
38 |                         -- and it's available
39 |                         maybeCachedModel
40 |                             |> Maybe.withDefault
41 |                                 {}
42 |                 in
43 |                 ( model
44 |                 , Effect.none
45 |                 )
46 |         , update =
47 |             \msg model ->
48 |                 ( model, Effect.none )
49 |         , subscriptions = \_ -> Listen.none
50 |         }
51 |         |> App.Store.withLocalStorage
52 |             { decoder = decoder
53 |             , encode = encode
54 |             }
55 | 
56 | 
57 | encode : Model -> Json.Encode.Value
58 | encode model =
59 |     Json.Encode.object []
60 | 
61 | 
62 | decoder : Json.Decode.Decoder Model
63 | decoder =
64 |     Json.Decode.succeed {}
65 | 


--------------------------------------------------------------------------------
/ext-generate/generator/app/templates/oneOff/effect.ts:
--------------------------------------------------------------------------------
1 | export const connect = (app: any) => {
2 |     // Listen for messages from Elm
3 |     app.ports?.{{name_decapitalized}}?.subscribe?.((message: any) => {
4 |         console.log("{{name_decapitalized}}", message);
5 |     });
6 | };
7 | 


--------------------------------------------------------------------------------
/ext-generate/generator/app/templates/toHidden/App/Store.elm:
--------------------------------------------------------------------------------
 1 | module App.Store exposing
 2 |     ( Store, store
 3 |     , withLocalStorage
 4 |     )
 5 | 
 6 | {-|
 7 | 
 8 | @docs Store, store
 9 | 
10 | @docs withLocalStorage
11 | 
12 | -}
13 | 
14 | import Effect
15 | import Json.Decode as Decode
16 | import Json.Encode as Json
17 | import Listen
18 | import Url
19 | 
20 | 
21 | {-| -}
22 | type alias Store msg model =
23 |     { init : Json.Value -> Url.Url -> Maybe model -> ( model, Effect.Effect msg )
24 |     , update : msg -> model -> ( model, Effect.Effect msg )
25 |     , subscriptions : model -> Listen.Listen msg
26 |     , codec :
27 |         Maybe
28 |             { decoder : Decode.Decoder model
29 |             , encode : model -> Json.Value
30 |             }
31 |     }
32 | 
33 | 
34 | {-| -}
35 | store :
36 |     { init : Json.Value -> Url.Url -> Maybe model -> ( model, Effect.Effect msg )
37 |     , update : msg -> model -> ( model, Effect.Effect msg )
38 |     , subscriptions : model -> Listen.Listen msg
39 |     }
40 |     -> Store msg model
41 | store options =
42 |     { init = options.init
43 |     , update = options.update
44 |     , subscriptions = options.subscriptions
45 |     , codec = Nothing
46 |     }
47 | 
48 | 
49 | {-| -}
50 | withLocalStorage :
51 |     { decoder : Decode.Decoder model
52 |     , encode : model -> Json.Value
53 |     }
54 |     -> Store msg model
55 |     -> Store msg model
56 | withLocalStorage codec res =
57 |     { res | codec = Just codec }
58 | 


--------------------------------------------------------------------------------
/ext-generate/generator/app/templates/toJs/js/effect/clipboard.ts:
--------------------------------------------------------------------------------
 1 | export const connect = (app: any, data: any) => {
 2 |   app.ports?.clipboard?.subscribe?.((message: any) => {
 3 |     copy(message);
 4 |   });
 5 | };
 6 | 
 7 | 
 8 | export function copy(text: string) {
 9 |   const clipboard = navigator.clipboard;
10 |   if (!clipboard) {
11 |     return;
12 |   }
13 |   clipboard.writeText(text);
14 | }
15 | 


--------------------------------------------------------------------------------
/ext-generate/generator/app/templates/toJs/js/effect/local-storage.ts:
--------------------------------------------------------------------------------
 1 | export const connect = (app: any, data: any) => {
 2 |   // Listen for messages from Elm
 3 |   app.ports?.localStorage?.subscribe?.((message: any) => {
 4 |     switch (message.operation) {
 5 |       case "save":
 6 |         set(message.details.key, message.details.value);
 7 |         if (app.ports?.localStorageUpdated) {
 8 |           app.ports.localStorageUpdated.send(message.details);
 9 |         }
10 |         break;
11 | 
12 |       case "clear":
13 |         clear(message.details.key);
14 |         break;
15 | 
16 |       default:
17 |         break;
18 |     }
19 |   });
20 | };
21 | 
22 | 
23 | // Actual commands
24 | export const getAll = () => {
25 |   const data: any = {};
26 |   for (var i = 0, len = localStorage.length; i < len; ++i) {
27 |     const key = localStorage.key(i);
28 |     if (key) {
29 |       data[key] = get(key);
30 |     }
31 |   }
32 |   return data;
33 | };
34 | 
35 | export const get = (key: string): any => {
36 |   const item = localStorage.getItem(key);
37 |   if (item) {
38 |     try {
39 |       return JSON.parse(item);
40 |     } catch (e) {
41 |       return null;
42 |     }
43 |   } else {
44 |     return null;
45 |   }
46 | };
47 | 
48 | export const set = (key: string, value: any) => {
49 |   localStorage.setItem(key, JSON.stringify(value));
50 | };
51 | 
52 | export const clear = (key: string) => {
53 |   localStorage.removeItem(key);
54 | };
55 | 


--------------------------------------------------------------------------------
/ext-generate/generator/app/templates/toJs/js/effect/scroll.ts:
--------------------------------------------------------------------------------
1 | export const connect = (app: any, data: any) => {
2 |     // Listen for messages from Elm
3 |     app.ports?.resetWindowScroll?.subscribe?.(() => {
4 |         window.scrollTo(0, 0);
5 |     });
6 | };
7 | 


--------------------------------------------------------------------------------
/ext-generate/generator/app/templates/toJs/js/effect/text-selection.ts:
--------------------------------------------------------------------------------
 1 | export const connect = (app: any, data: any) => {
 2 |   // Listen for messages from Elm
 3 |   app.ports?.textSelection?.subscribe?.((message: any) => {
 4 |     focus_and_select(message.id);
 5 |   });
 6 | };
 7 | 
 8 | 
 9 | 
10 | export function focus_and_select(id: string) {
11 |   setTimeout(() => {
12 |     // in some cases the element hasn't been rendered yet
13 |     const elem = document.getElementById(id);
14 |     if (elem) {
15 |       elem.focus();
16 |       (elem as HTMLInputElement).select();
17 |     }
18 |   }, 100);
19 | }
20 | 


--------------------------------------------------------------------------------
/ext-generate/generator/app/templates/toJs/js/effects.ts:
--------------------------------------------------------------------------------
 1 | /// 
 2 | 
 3 | // This imports all effect modules in the effect directory
 4 | // and calls connect on them.
 5 | export function connect(app: any, data: any) {
 6 |   const modules = import.meta.glob("./effect/*.ts", { eager: true });
 7 |   for (const module of Object.values(modules)) {
 8 |     if ("connect" in module && module.connect && typeof module.connect === 'function') {
 9 |       module.connect(app, data);
10 |     } else {
11 |       console.log(`${module} does not have a connect function`);
12 |     }
13 |   }
14 | }
15 | 


--------------------------------------------------------------------------------
/ext-generate/generator/app/templates/toJs/js/webcomponents/index.ts:
--------------------------------------------------------------------------------
1 | // import TipTap from "./js/tiptap";
2 | import ElmPortal from "./elm-portal";
3 | 
4 | export default function include() {
5 |   ElmPortal({ mountId: "elm-portal-target" });
6 |   // TipTap();
7 | }
8 | 


--------------------------------------------------------------------------------
/ext-generate/generator/app/templates/toJs/main.ts:
--------------------------------------------------------------------------------
 1 | // @ts-ignore
 2 | import Elm from "../elm-stuff/generated/Main.elm";
 3 | import * as LocalStorage from "./js/effect/local-storage";
 4 | import * as Effects from "./js/effects";
 5 | import Webcomponents from "./js/webcomponents";
 6 | 
 7 | // Import all generated CSS files
 8 | import.meta.glob("../elm-stuff/generated/**/*.css", { eager: true });
 9 | 
10 | // Include any custom elements we need.
11 | Webcomponents();
12 | 
13 | // Boot up the Elm App
14 | const app = Elm.Main.init({
15 |   flags: { now: Date.now(), localStorage: LocalStorage.getAll() },
16 | });
17 | 
18 | // Connect all effects
19 | Effects.connect(app, {});
20 | 


--------------------------------------------------------------------------------
/ext-generate/generator/app/templates/toRoot/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | elm-stuff
3 | dist
4 | 


--------------------------------------------------------------------------------
/ext-generate/generator/app/templates/toRoot/index.html:
--------------------------------------------------------------------------------
1 | 
2 |     
3 |         
4 |         My Elm App
5 |         
6 |     
7 |     
8 | 
9 | 


--------------------------------------------------------------------------------
/ext-generate/generator/app/templates/toRoot/tsconfig.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "ES2020",
 4 |     "useDefineForClassFields": true,
 5 |     "module": "CommonJS",
 6 |     "lib": ["ES2020", "DOM", "DOM.Iterable"],
 7 |     "skipLibCheck": true,
 8 | 
 9 |     "allowImportingTsExtensions": true,
10 |     "resolveJsonModule": true,
11 |     "isolatedModules": true,
12 |     "noEmit": true,
13 | 
14 |     /* Linting */
15 |     "strict": true,
16 |     "noUnusedLocals": true,
17 |     "noFallthroughCasesInSwitch": true
18 |   },
19 | 
20 |   "include": ["src"]
21 | }
22 | 


--------------------------------------------------------------------------------
/ext-generate/generator/app/templates/toRoot/vite.config.js:
--------------------------------------------------------------------------------
 1 | import { defineConfig } from "vite";
 2 | import elmDevPlugin from "./viteElm";
 3 | 
 4 | 
 5 | export default defineConfig(({ mode }) => {
 6 |   const isDev = mode == "development";
 7 |   return {
 8 |     clearScreen: false,
 9 |     server: {
10 |       strictPort: true,
11 |       open: true,
12 |     },
13 | 
14 |     build: {
15 |       minify: "esbuild",
16 |       outDir: "dist",
17 |     },
18 | 
19 |     plugins: [
20 |       elmDevPlugin({
21 |         debug: isDev,
22 |         optimize: !isDev,
23 |       }),
24 |     ],
25 |   };
26 | });
27 | 


--------------------------------------------------------------------------------
/ext-generate/generator/build.sh:
--------------------------------------------------------------------------------
 1 | cd codegen;
 2 | rm -rf Gen;
 3 | elm-codegen install;
 4 | cd ..;
 5 | 
 6 | 
 7 | bun run typecheck
 8 | 
 9 | rm -rf dist
10 | elm make main/Run.elm --output=dist/generate.js --optimize
11 | bun build ./index.ts --outfile=dist/run.js
12 | 
13 | # To reduce confusion, remove the intermediate file.
14 | rm ./dist/generate.js
15 | 
16 | # Generate random version string and update Javascript.hs
17 | RANDOM_VERSION=$(openssl rand -hex 8)
18 | sed -i '' "s/version = \".*\"/version = \"$RANDOM_VERSION\"/" ../Gen/Javascript.hs
19 | sed -i '' "s/version = \".*\"/version = \"$RANDOM_VERSION\"/" ../Gen/Templates.hs
20 | 


--------------------------------------------------------------------------------
/ext-generate/generator/codegen/elm.codegen.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "elm-codegen-version": "0.4.1",
 3 |   "codegen-helpers": {
 4 |     "packages": {
 5 |       "elm/core": "1.0.5",
 6 |       "elm/url": "1.0.0",
 7 |       "elm/browser": "1.0.2",
 8 |       "elm/json": "1.1.3",
 9 |       "elm/html": "1.0.0",
10 |       "elm/http": "2.0.0",
11 |       "dillonkearns/elm-markdown": "7.0.1",
12 |       "lydell/elm-app-url": "1.0.2"
13 |     },
14 |     "local": [
15 |       "../app/templates/toHidden/",
16 |       "../app/templates/customizable/",
17 |       "/Users/griff/projects/elm-ui/docs.json"
18 |     ]
19 |   }
20 | }


--------------------------------------------------------------------------------
/ext-generate/generator/dev/Generate.elm:
--------------------------------------------------------------------------------
 1 | module Generate exposing (..)
 2 | 
 3 | -- import Interactive
 4 | 
 5 | import Elm
 6 | import Exemplar
 7 | import Gen.CodeGen.Generate as Generate
 8 | import Generate.PageId
 9 | import Interactive
10 | import Json.Decode
11 | import Options
12 | 
13 | 
14 | main : Program Json.Decode.Value () ()
15 | main =
16 |     Generate.fromJson Options.decoder
17 |         (\options ->
18 |             let
19 |                 _ =
20 |                     Debug.log "options" options
21 |             in
22 |             Generate.PageId.generate options
23 |                 :: List.map renderExampleModule options.project
24 |         )
25 | 
26 | 
27 | renderExampleModule : Elm.Docs.Module -> Elm.File
28 | renderExampleModule mod =
29 |     case Exemplar.interactiveAll mod of
30 |         Err err ->
31 |             Elm.file [ "Live" ]
32 |                 [ Elm.declaration "error"
33 |                     (Elm.string err)
34 |                 ]
35 | 
36 |         Ok interactives ->
37 |             Interactive.generate ("Dev" :: String.split "." interactives.name)
38 |                 interactives
39 | 


--------------------------------------------------------------------------------
/ext-generate/generator/dev/Generate/PageId.elm:
--------------------------------------------------------------------------------
 1 | module Generate.PageId exposing (generate)
 2 | 
 3 | {-| -}
 4 | 
 5 | import Elm
 6 | import Elm.Docs
 7 | import Options
 8 | 
 9 | 
10 | generate : Options.Options -> Elm.File
11 | generate options =
12 |     Elm.file [ "Dev", "Page", "Id" ]
13 |         [ Elm.customType "Id"
14 |             (List.map
15 |                 (\mod ->
16 |                     Elm.variant
17 |                         (String.join "_"
18 |                             (String.split "." mod.name)
19 |                         )
20 |                 )
21 |                 options.project
22 |             )
23 |             |> Elm.expose
24 |         ]
25 | 


--------------------------------------------------------------------------------
/ext-generate/generator/dev/Options.elm:
--------------------------------------------------------------------------------
 1 | module Options exposing (Options, decoder)
 2 | 
 3 | import Elm.Docs
 4 | import Json.Decode
 5 | 
 6 | 
 7 | type alias Options =
 8 |     { output : String
 9 |     , project : List Elm.Docs.Module
10 |     , viewers : List Elm.Docs.Module
11 |     }
12 | 
13 | 
14 | decoder : Json.Decode.Decoder Options
15 | decoder =
16 |     Json.Decode.map3 Options
17 |         (Json.Decode.field "output" Json.Decode.string)
18 |         (Json.Decode.field "project"
19 |             (Json.Decode.list Elm.Docs.decoder)
20 |         )
21 |         (Json.Decode.field "viewers"
22 |             (Json.Decode.list Elm.Docs.decoder)
23 |         )
24 | 


--------------------------------------------------------------------------------
/ext-generate/generator/dev/elm.codegen.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "elm-codegen-version": "0.4.1",
 3 |   "codegen-helpers": {
 4 |     "packages": {
 5 |       "elm/core": "1.0.5",
 6 |       "elm/url": "1.0.0",
 7 |       "elm/browser": "1.0.2",
 8 |       "elm/json": "1.1.3",
 9 |       "elm/html": "1.0.0",
10 |       "elm/http": "2.0.0",
11 |       "mdgriffith/elm-codegen": "4.0.1",
12 |       "dillonkearns/elm-markdown": "7.0.1",
13 |       "lydell/elm-app-url": "1.0.2",
14 |       "elm/parser": "1.1.0"
15 |     },
16 |     "local": [
17 |       "/Users/mattgriffith/projects/mdgriffith/elm-ui/docs.json",
18 |       "./engine/Ui/Theme/Input.elm",
19 |       "../../plugins/app/templates/toCopy/App/Page.elm",
20 |       "../../plugins/app/templates/toCopy/App/Effect.elm",
21 |       "../../plugins/app/templates/toCopy/App/Sub.elm",
22 |       "../../plugins/app/templates/toCopy/App/View.elm"
23 |     ]
24 |   }
25 | }
26 | 


--------------------------------------------------------------------------------
/ext-generate/generator/dev/elm.json:
--------------------------------------------------------------------------------
 1 | {
 2 |     "type": "application",
 3 |     "source-directories": [
 4 |         "."
 5 |     ],
 6 |     "elm-version": "0.19.1",
 7 |     "dependencies": {
 8 |         "direct": {
 9 |             "dillonkearns/elm-markdown": "7.0.1",
10 |             "elm/browser": "1.0.2",
11 |             "elm/core": "1.0.5",
12 |             "elm/html": "1.0.0",
13 |             "elm/json": "1.1.3",
14 |             "elm/parser": "1.1.0",
15 |             "elm/project-metadata-utils": "1.0.2",
16 |             "mdgriffith/elm-codegen": "4.0.1"
17 |         },
18 |         "indirect": {
19 |             "elm/regex": "1.0.0",
20 |             "elm/time": "1.0.0",
21 |             "elm/url": "1.0.0",
22 |             "elm/virtual-dom": "1.0.2",
23 |             "elm-community/basics-extra": "4.1.0",
24 |             "elm-community/list-extra": "8.6.0",
25 |             "miniBill/elm-unicode": "1.0.2",
26 |             "rtfeldman/elm-hex": "1.0.0",
27 |             "stil4m/elm-syntax": "7.2.9",
28 |             "stil4m/structured-writer": "1.0.3",
29 |             "the-sett/elm-pretty-printer": "3.0.0"
30 |         }
31 |     },
32 |     "test-dependencies": {
33 |         "direct": {},
34 |         "indirect": {}
35 |     }
36 | }
37 | 


--------------------------------------------------------------------------------
/ext-generate/generator/elm.json:
--------------------------------------------------------------------------------
 1 | {
 2 |     "type": "application",
 3 |     "source-directories": [
 4 |         "main",
 5 |         "app",
 6 |         "assets",
 7 |         "routes",
 8 |         "theme",
 9 |         "common",
10 |         "codegen",
11 |         "docs"
12 |     ],
13 |     "elm-version": "0.19.1",
14 |     "dependencies": {
15 |         "direct": {
16 |             "avh4/elm-color": "1.0.0",
17 |             "dillonkearns/elm-markdown": "7.0.1",
18 |             "elm/browser": "1.0.2",
19 |             "elm/core": "1.0.5",
20 |             "elm/html": "1.0.0",
21 |             "elm/json": "1.1.3",
22 |             "elm/parser": "1.1.0",
23 |             "elm/project-metadata-utils": "1.0.2",
24 |             "mdgriffith/elm-codegen": "5.1.1"
25 |         },
26 |         "indirect": {
27 |             "elm/regex": "1.0.0",
28 |             "elm/time": "1.0.0",
29 |             "elm/url": "1.0.0",
30 |             "elm/virtual-dom": "1.0.2",
31 |             "elm-community/basics-extra": "4.1.0",
32 |             "elm-community/list-extra": "8.6.0",
33 |             "miniBill/elm-unicode": "1.0.2",
34 |             "rtfeldman/elm-hex": "1.0.0",
35 |             "stil4m/elm-syntax": "7.2.9",
36 |             "stil4m/structured-writer": "1.0.3",
37 |             "the-sett/elm-pretty-printer": "3.0.0"
38 |         }
39 |     },
40 |     "test-dependencies": {
41 |         "direct": {
42 |             "elm-explorations/test": "2.2.0"
43 |         },
44 |         "indirect": {
45 |             "elm/bytes": "1.0.8",
46 |             "elm/random": "1.0.0"
47 |         }
48 |     }
49 | }
50 | 


--------------------------------------------------------------------------------
/ext-generate/generator/package.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "name": "generator",
 3 |   "module": "index.ts",
 4 |   "type": "module",
 5 |   "scripts": {
 6 |     "typecheck": "tsc --noEmit",
 7 |     "build": "bash build.sh"
 8 |   },
 9 |   "devDependencies": {
10 |     "@types/bun": "latest",
11 |     "bun-types": "^1.2.3"
12 |   },
13 |   "peerDependencies": {
14 |     "typescript": "^5.7.3"
15 |   },
16 |   "dependencies": {
17 |     "chalk": "^5.4.1",
18 |     "zod": "^3.24.2"
19 |   }
20 | }


--------------------------------------------------------------------------------
/ext-generate/generator/theme/Theme/Generate.elm:
--------------------------------------------------------------------------------
 1 | module Theme.Generate exposing (..)
 2 | 
 3 | import Elm
 4 | import Theme
 5 | import Theme.Generate.Ui
 6 | 
 7 | 
 8 | generate : Theme.Theme -> List Elm.File
 9 | generate theme =
10 |     Theme.Generate.Ui.generate theme
11 | 


--------------------------------------------------------------------------------
/ext-generate/generator/theme/elm.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "type": "application",
 3 |   "source-directories": [".", ".."],
 4 |   "elm-version": "0.19.1",
 5 |   "dependencies": {
 6 |     "direct": {
 7 |       "dillonkearns/elm-markdown": "7.0.1",
 8 |       "elm/browser": "1.0.2",
 9 |       "elm/core": "1.0.5",
10 |       "elm/html": "1.0.0",
11 |       "elm/json": "1.1.3",
12 |       "elm/parser": "1.1.0",
13 |       "mdgriffith/elm-codegen": "4.0.1"
14 |     },
15 |     "indirect": {
16 |       "elm/regex": "1.0.0",
17 |       "elm/time": "1.0.0",
18 |       "elm/url": "1.0.0",
19 |       "elm/virtual-dom": "1.0.2",
20 |       "elm-community/basics-extra": "4.1.0",
21 |       "elm-community/list-extra": "8.6.0",
22 |       "miniBill/elm-unicode": "1.0.2",
23 |       "rtfeldman/elm-hex": "1.0.0",
24 |       "stil4m/elm-syntax": "7.2.9",
25 |       "stil4m/structured-writer": "1.0.3",
26 |       "the-sett/elm-pretty-printer": "3.0.0"
27 |     }
28 |   },
29 |   "test-dependencies": {
30 |     "direct": {},
31 |     "indirect": {}
32 |   }
33 | }
34 | 


--------------------------------------------------------------------------------
/ext-generate/generator/theme/templates/customizable/Ui/Divider.elm:
--------------------------------------------------------------------------------
 1 | module Ui.Divider exposing (horizontal, vertical)
 2 | 
 3 | {-| -}
 4 | 
 5 | import Ui
 6 | import Ui.Theme
 7 | import Ui.Theme.Palette
 8 | 
 9 | 
10 | {-| -}
11 | horizontal : Ui.Element msg
12 | horizontal =
13 |     Ui.el
14 |         [ Ui.height (Ui.px 1)
15 |         , Ui.width Ui.fill
16 |         , Ui.Theme.Palette.neutralInverted
17 |         ]
18 |         Ui.none
19 | 
20 | 
21 | {-| -}
22 | vertical : Ui.Element msg
23 | vertical =
24 |     Ui.el
25 |         [ Ui.width (Ui.px 1)
26 |         , Ui.height Ui.fill
27 |         , Ui.Theme.Palette.neutralInverted
28 |         ]
29 |         Ui.none
30 | 


--------------------------------------------------------------------------------
/ext-generate/generator/theme/templates/customizable/Ui/Dropdown.elm:
--------------------------------------------------------------------------------
 1 | module Ui.Dropdown exposing (Visible, init, withMenu)
 2 | 
 3 | {-| This is for attaching a dropdown menu
 4 | -}
 5 | 
 6 | import Ui
 7 | import WebComponent.Portal
 8 | 
 9 | 
10 | init : Visible
11 | init =
12 |     Visible WebComponent.Portal.closed
13 | 
14 | 
15 | type Visible
16 |     = Visible WebComponent.Portal.Model
17 | 
18 | 
19 | withMenu :
20 |     { open : Visible
21 |     , onOpen : Visible -> msg
22 |     , menu : Ui.Element msg
23 |     }
24 |     -> Ui.Element msg
25 |     -> Ui.Element msg
26 | withMenu options root =
27 |     Ui.html <|
28 |         WebComponent.Portal.view
29 |             { position = WebComponent.Portal.ToRightOf
30 |             , model =
31 |                 case options.open of
32 |                     Visible portal ->
33 |                         portal
34 |             , onMsg = options.onOpen << Visible
35 |             , button = Ui.embed [] root
36 |             , menu = Ui.embed [] options.menu
37 |             }
38 | 


--------------------------------------------------------------------------------
/ext-generate/generator/theme/templates/customizable/Ui/Modal.elm:
--------------------------------------------------------------------------------
 1 | module Ui.Modal exposing
 2 |     ( Modal, modal
 3 |     , withCloseOnBackdropClick
 4 |     , view
 5 |     )
 6 | 
 7 | {-|
 8 | 
 9 | @docs Modal, modal
10 | 
11 | @docs withCloseOnBackdropClick
12 | 
13 | @docs view
14 | 
15 | -}
16 | 
17 | import Ui
18 | import Ui.Input
19 | import Ui.Theme
20 | 
21 | 
22 | type Modal msg
23 |     = Modal (Details msg)
24 | 
25 | 
26 | type alias Details msg =
27 |     { visible : Bool
28 |     , closeOnClickBackdrop : Maybe (Bool -> msg)
29 |     , content : Ui.Element msg
30 |     }
31 | 
32 | 
33 | {-| -}
34 | modal :
35 |     { visible : Bool
36 |     , content : Ui.Element msg
37 |     }
38 |     -> Switch msg
39 | modal options =
40 |     Modal
41 |         { visible = options.visible
42 |         , content = options.content
43 |         , closeOnClickBackdrop = Nothing
44 |         }
45 | 
46 | 
47 | withCloseOnBackdropClick : (Bool -> msg) -> Modal msg -> Modal msg
48 | withCloseOnBackdropClick closeOnClickBackdrop (Modal details) =
49 |     Modal
50 |         { details
51 |             | closeOnClickBackdrop = Just closeOnClickBackdrop
52 |         }
53 | 
54 | 
55 | {-| -}
56 | view : Modal msg -> Ui.Element msg
57 | view (Modal options) =
58 |     Ui.el
59 |         [ Ui.width Ui.fill
60 |         , Ui.height Ui.fill
61 |         , Ui.Theme.background.backdrop
62 |         , case options.closeOnClickBackdrop of
63 |             Nothing ->
64 |                 Ui.noAttr
65 | 
66 |             Just msg ->
67 |                 -- TODO: Ui.clickOnThisElement?
68 |                 Ui.onClick msg
69 |         ]
70 |         (Ui.el
71 |             [ Ui.width (Ui.px 800)
72 |             , Ui.height (Ui.px 600)
73 |             , Ui.centerX
74 |             , Ui.centerY
75 |             ]
76 |             options.content
77 |         )
78 | 


--------------------------------------------------------------------------------
/ext-generate/generator/theme/templates/customizable/Ui/Tooltip.elm:
--------------------------------------------------------------------------------
 1 | module Ui.Tooltip exposing (..)
 2 | 
 3 | {-| -}
 4 | 
 5 | import Ui
 6 | import Ui.Theme
 7 | import Ui.Theme.Palette
 8 | import WebComponents.Portal as Portal
 9 | 
10 | 
11 | {-| -}
12 | tooltip : String -> Ui.Attribute msg
13 | tooltip label =
14 |     Ui.above
15 |         (Ui.el [ Ui.Theme.Palette.neutralInverted ]
16 |             (Ui.text label)
17 |         )
18 | 


--------------------------------------------------------------------------------
/ext-generate/generator/tsconfig.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "compilerOptions": {
 3 |     // Enable latest features
 4 |     "lib": [
 5 |       "ESNext",
 6 |       "DOM",
 7 |       "DOM.Iterable"
 8 |     ],
 9 |     "target": "ESNext",
10 |     "module": "ESNext",
11 |     "moduleDetection": "force",
12 |     "types": [
13 |       "bun-types"
14 |     ],
15 |     "jsx": "react-jsx",
16 |     "allowJs": true,
17 |     // Bundler mode
18 |     "moduleResolution": "bundler",
19 |     "allowImportingTsExtensions": true,
20 |     "verbatimModuleSyntax": true,
21 |     "noEmit": true,
22 |     // Best practices
23 |     "strict": true,
24 |     "skipLibCheck": true,
25 |     "noFallthroughCasesInSwitch": true,
26 |     // Some stricter flags
27 |     "noUnusedLocals": true,
28 |     "noUnusedParameters": true,
29 |     "noPropertyAccessFromIndexSignature": true
30 |   },
31 |   "include": [
32 |     "index.ts",
33 |     "options.ts"
34 |   ],
35 |   "exclude": [
36 |     "node_modules",
37 |     "dist"
38 |   ]
39 | }


--------------------------------------------------------------------------------
/ext-sentry/Ext/Sentry.hs:
--------------------------------------------------------------------------------
 1 | {-# LANGUAGE OverloadedStrings #-}
 2 | 
 3 | module Ext.Sentry where
 4 | 
 5 | import Control.Concurrent.MVar
 6 | 
 7 | import qualified Data.ByteString as BS
 8 | import qualified Data.ByteString.Builder as B
 9 | 
10 | import Control.Exception
11 | import Formatting
12 | import Formatting.Clock
13 | import System.Clock
14 | import Json.Encode ((==>))
15 | import qualified Json.Encode as Encode
16 | 
17 | 
18 | data Cache =
19 |   Cache
20 |     { jsOutput :: MVar BS.ByteString
21 |     , compileResult :: MVar (Either Encode.Value Encode.Value)
22 |     }
23 | 
24 | 
25 | instance Show Cache where
26 |   show _ = ""
27 | 
28 | 
29 | init :: IO Cache
30 | init = do
31 |   mJsOutput <- newMVar ""
32 |   -- @TODO watchtower specific? or invert so its not.
33 |   mCompileresult <- newMVar $ Right $ Encode.object [ "compiled" ==> (Encode.bool True) ]
34 |   pure $ Cache mJsOutput mCompileresult
35 | 
36 | 
37 | updateCompileResult :: Cache -> IO (Either Encode.Value Encode.Value) -> IO ()
38 | updateCompileResult (Cache _ compileResult) action = do
39 |   modifyMVar_ compileResult (\_ -> action )
40 | 
41 | 
42 | getCompileResult :: Cache -> IO (Either Encode.Value Encode.Value)
43 | getCompileResult cache =
44 |   readMVar $ compileResult cache
45 | 
46 | 
47 | getJsOutput :: Cache -> IO BS.ByteString
48 | getJsOutput cache =
49 |   readMVar $ jsOutput cache
50 | 
51 | 
52 | updateJsOutput :: Cache -> IO BS.ByteString -> IO ()
53 | updateJsOutput (Cache mJsOutput _) recompile = do
54 |   modifyMVar_ mJsOutput (\_ -> recompile )
55 | 


--------------------------------------------------------------------------------
/ext-sentry/readme.md:
--------------------------------------------------------------------------------
1 | 
2 | ### Sentry: Elm Compilation Server
3 | 
4 | - File watcher + optimistic compiler for ultra-fast recompiles
5 | - In-memory type cache for ultra-fast type and project code queries (WIP)
6 | 


--------------------------------------------------------------------------------
/ext-watchtower/README.md:
--------------------------------------------------------------------------------
1 | ## Watchtower
2 | 
3 | Watchtower is fancy name for the dev server.
4 | 
5 | Start it by running `elm-dev server`
6 | 
7 | 


--------------------------------------------------------------------------------
/ext-watchtower/Watchtower/Editor.hs:
--------------------------------------------------------------------------------
 1 | {-# LANGUAGE OverloadedStrings #-}
 2 | 
 3 | module Watchtower.Editor where
 4 | 
 5 | {-| Data for communicating positions with the editor
 6 | 
 7 | 
 8 | -}
 9 | 
10 | import qualified Reporting.Annotation as Ann
11 | import qualified Json.Decode
12 | import qualified Json.String
13 | import qualified Json.Encode
14 | import Json.Encode ((==>))
15 | import Control.Applicative ((<|>), (<$>), (<*>))
16 | 
17 | import StandaloneInstances
18 | 
19 | 
20 | data PointLocation =
21 |     PointLocation
22 |         { _pointfile :: FilePath
23 |         , _position :: Ann.Position
24 |         }
25 | 
26 | 
27 | 
28 | 
29 | -- ENCODERS
30 | 
31 | 
32 | encodeRegion :: Ann.Region -> Json.Encode.Value
33 | encodeRegion (Ann.Region start end) =
34 |     Json.Encode.object
35 |         [ ("start" ==> encodePosition start)
36 |         , ("end" ==> encodePosition end)
37 |         ]
38 | 
39 | 
40 | encodePosition :: Ann.Position -> Json.Encode.Value
41 | encodePosition (Ann.Position row col) =
42 |     Json.Encode.object
43 |         [ ("line" ==> Json.Encode.int (fromIntegral row))
44 |         , ("column" ==> Json.Encode.int (fromIntegral col))
45 |         ]
46 | 
47 | 
48 | 
49 | -- DECODERS
50 | 
51 | decodeRegion :: Json.Decode.Decoder x Ann.Region
52 | decodeRegion =
53 |     Ann.Region
54 |         <$> (Json.Decode.field "start" decodePosition)
55 |         <*> (Json.Decode.field "end" decodePosition)
56 | 
57 | 
58 | decodePosition :: Json.Decode.Decoder x Ann.Position
59 | decodePosition =
60 |     Ann.Position
61 |         <$> (Json.Decode.field "line" (fmap fromIntegral Json.Decode.int))
62 |         <*> (Json.Decode.field "column" (fmap fromIntegral Json.Decode.int))


--------------------------------------------------------------------------------
/ext-watchtower/Watchtower/State/Project.hs:
--------------------------------------------------------------------------------
 1 | module Watchtower.State.Project (upsert) where
 2 | 
 3 | import qualified Control.Concurrent.STM as STM
 4 | import qualified Data.List as List
 5 | import qualified Ext.Dev.Project
 6 | import qualified Ext.Sentry
 7 | import qualified Data.NonEmptyList as NE
 8 | import qualified Watchtower.Live.Client as Client
 9 | 
10 | 
11 | upsert :: Client.State -> FilePath -> NE.List FilePath -> IO Client.ProjectCache
12 | upsert state@(Client.State mClients mProjects) root entrypoints = do
13 | 
14 |     sentryCache <- Ext.Sentry.init
15 |     let newProject = Ext.Dev.Project.Project root root entrypoints
16 |     let newProjectCache = Client.ProjectCache newProject sentryCache
17 | 
18 |     STM.atomically $ do
19 |         existingProjects <- STM.readTVar mProjects
20 |         case List.find (Client.matchingProject newProjectCache) existingProjects of
21 |             Just existingProject -> do
22 |                 pure existingProject
23 |             Nothing -> do
24 |                 STM.writeTVar mProjects (newProjectCache : existingProjects)
25 |                 pure newProjectCache


--------------------------------------------------------------------------------
/ext-watchtower/Watchtower/Test.hs:
--------------------------------------------------------------------------------
 1 | module Watchtower.Test where
 2 | 
 3 | import Control.Concurrent (threadDelay)
 4 | import qualified Control.Exception
 5 | import Ext.Common
 6 | import qualified Ext.CompileMode
 7 | import qualified Ext.Log
 8 | import qualified System.Directory as Dir
 9 | import qualified System.Environment as Env
10 | import qualified Watchtower.Server
11 | 
12 | {-
13 | 
14 | Allows us to use `:rr` in GHCI to quickly kill, typecheck, rebuild & reboot the server,
15 | without having to build a binary and reboot it in shell.
16 | 
17 | -}
18 | 
19 | serve :: IO ()
20 | serve = do
21 |   projectDir <-
22 |     Control.Exception.catch
23 |       (Env.lookupEnv "ELM_WATCHTOWER_START_PROJECT")
24 |       (const $ pure Nothing :: Control.Exception.IOException -> IO (Maybe String))
25 |   -- Ext.CompileMode.setModeDisk
26 |   Ext.CompileMode.setModeMemory
27 |   trackedForkIO
28 |     $ Ext.Log.withAllBut
29 |       []
30 |     -- Add any flags to exclude here!
31 |     $ Watchtower.Server.serve
32 |       projectDir
33 |       (Watchtower.Server.Flags (Just 51213))
34 | 


--------------------------------------------------------------------------------
/ext-watchtower/Watchtower/Version.hs:
--------------------------------------------------------------------------------
 1 | {-# LANGUAGE TemplateHaskell #-}
 2 | 
 3 | module Watchtower.Version where
 4 | 
 5 | import GitHash
 6 | 
 7 | short :: String
 8 | short = "0.0.1"
 9 | 
10 | full :: String
11 | full =
12 |   let
13 |     gi = $$tGitInfoCwd
14 |     dirty | giDirty gi = "-dirty"
15 |           | otherwise  = ""
16 |   in
17 |   concat
18 |     [ "watchtower-", short, "-", giHash gi, dirty
19 |     , " (", giCommitDate gi, ")"
20 |     , " (branch:", giBranch gi, ")"
21 |     ]
22 | 


--------------------------------------------------------------------------------
/hints/repl.md:
--------------------------------------------------------------------------------
 1 | 
 2 | # REPL
 3 | 
 4 | The REPL lets you interact with Elm values and functions in your terminal.
 5 | 
 6 | 
 7 | ## Use
 8 | 
 9 | You can type in expressions, definitions, custom types, and module imports using normal Elm syntax.
10 | 
11 | ```elm
12 | > 1 + 1
13 | 2 : number
14 | 
15 | > "hello" ++ "world"
16 | "helloworld" : String
17 | ```
18 | 
19 | The same can be done with definitions and custom types:
20 | 
21 | ```elm
22 | > fortyTwo = 42
23 | 42 : number
24 | 
25 | > increment n = n + 1
26 |  : number -> number
27 | 
28 | > increment 41
29 | 42 : number
30 | 
31 | > factorial n =
32 | |   if n < 1 then
33 | |     1
34 | |   else
35 | |     n * factorial (n-1)
36 | |
37 |  : number -> number
38 | 
39 | > factorial 5
40 | 120 : number
41 | 
42 | > type User
43 | |   = Regular String
44 | |   | Visitor String
45 | |
46 | 
47 | > case Regular "Tom" of
48 | |   Regular name -> "Hey again!"
49 | |   Visitor name -> "Nice to meet you!"
50 | |
51 | "Hey again!" : String
52 | ```
53 | 
54 | When you run `elm repl` in a project with an [`elm.json`](https://github.com/elm/compiler/blob/master/docs/elm.json/application.md) file, you can import any module available in the project. So if your project has an `elm/html` dependency, you could say:
55 | 
56 | ```elm
57 | > import Html exposing (Html)
58 | 
59 | > Html.text "hello"
60 |  : Html msg
61 | 
62 | > Html.text
63 |  : String -> Html msg
64 | ```
65 | 
66 | If you create a module in your project named `MyThing` in your project, you can say `import MyThing` in the REPL as well. Any module that is accessible in your project should be accessible in the REPL.
67 | 
68 | 
69 | ## Exit
70 | 
71 | To exit the REPL, you can type `:exit`.
72 | 
73 | You can also press `ctrl-d` or `ctrl-c` on some platforms.
74 | 


--------------------------------------------------------------------------------
/hints/tuples.md:
--------------------------------------------------------------------------------
 1 | 
 2 | # From Tuples to Records
 3 | 
 4 | The largest tuple possible in Elm has three entries. Once you get to four, it is best to make a record with named entries.
 5 | 
 6 | For example, it is _conceivable_ to represent a rectangle as four numbers like `(10,10,100,100)` but it would be more self-documenting to use a record like this:
 7 | 
 8 | ```elm
 9 | type alias Rectangle =
10 |   { x : Float
11 |   , y : Float
12 |   , width : Float
13 |   , height : Float
14 |   }
15 | ```
16 | 
17 | Now it is clear that the dimensions should be `Float` values. It is also clear that we are not using the convention of specifying the top-left and bottom-right corners. It could be clearer about whether the `x` and `y` is the point in the top-left or in the middle though!
18 | 
19 | Anyway, using records like this also gives you access to syntax like `rect.x`, `.x`, and `{ rect | x = 40 }`. It is not clear how to design features like that for arbitrarily sized tuples, so we did not. We already have a way, and it is more self-documenting!
20 | 


--------------------------------------------------------------------------------
/installers-elm-dev/npm/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | packages/*/elm-dev
3 | packages/*/elm-dev.exe
4 | releases


--------------------------------------------------------------------------------
/installers-elm-dev/npm/.npmignore:
--------------------------------------------------------------------------------
1 | README.md
2 | .gitignore
3 | .git
4 | 


--------------------------------------------------------------------------------
/installers-elm-dev/npm/README.md:
--------------------------------------------------------------------------------
 1 | # Elm Dev
 2 | 
 3 | Elm Dev is a version of the Elm compiler that is made to support editing tools.
 4 | 
 5 | Not to be confused with Elm itself which lives here: https://elm-lang.org/
 6 | 
 7 | This package is for toolmakers, so if you're just starting out using Elm, you likely don't need this tool directly.
 8 | 
 9 | Install via `npm install -g elm-dev` if you want to play with it. It's currently experimental, but will likely be stable soon.
10 | 
11 | Currently this is a command line tool with the following commands that print or output JSON.
12 | 
13 | - `warnings` - List missing type signatures and unused values.
14 | - `entrypoints` - Detect what `.elm` files are the potential roots of a project. This will also report any ports relevant to a specific entrypoint as well as the type signatures of those ports.
15 | - `docs` - Generate `docs.json` for any package, or any local `.elm` file.
16 | - `imports` - Given a list of modules, report all files and packages that they collectively depends on. This is useful for
17 | - `usage` - Given a module, return all usages of that module in a given project.
18 | - `explain` - Given a fully qualified type name, provide it's full definition.
19 | 
20 | Each command may instead report compilation errors if the file or project fails to compile.
21 | 
22 | ## Roadmap
23 | 
24 | The above functionality is a first pass on what would be useful for `elm-dev` to report and has been published to allow downstream projects to try stuff out.
25 | 
26 | In the medium term, the intention is to support the language-server protocol and to adjust functionaltiy based on downstream projects.
27 | 


--------------------------------------------------------------------------------
/installers-elm-dev/npm/bin/elm-dev:
--------------------------------------------------------------------------------
 1 | #!/usr/bin/env node
 2 | 
 3 | var child_process = require('child_process');
 4 | 
 5 | 
 6 | // Some npm users enable --ignore-scripts (a good security measure) so
 7 | // they do not run the post-install hook and install.js does not run.
 8 | // Instead they will run this script.
 9 | //
10 | // On Mac and Linux, we hard link the elm executable into the exact same
11 | // location as this file. Since npm uses symlinks on these platforms,
12 | // that means that the first run will invoke this file and subsequent
13 | // runs will call the elm binary directly.
14 | //
15 | // On Windows, our binary file must be named elm.exe for it to run properly.
16 | // Instead of symlinks, npm creates two files:
17 | //
18 | //   - node_modules/.bin/elm (a bash file)
19 | //   - node_modules/.bin/elm.cmd (a batch file)
20 | //
21 | // Both files specifically invoke `node` to run the file listed at package.bin,
22 | // so there is no way around instantiating node for no reason on Windows.
23 | 
24 | 
25 | var binaryPath = require('../binary.js')();
26 | child_process
27 | 	.spawn(binaryPath, process.argv.slice(2), { stdio: 'inherit' })
28 | 	.on('exit', process.exit);
29 | 


--------------------------------------------------------------------------------
/installers-elm-dev/npm/install.js:
--------------------------------------------------------------------------------
1 | require('./binary.js')();
2 | 


--------------------------------------------------------------------------------
/installers-elm-dev/npm/package.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "name": "elm-dev",
 3 |   "version": "0.1.3",
 4 |   "description": "Elm Dev: a version of the Elm compiler to help with editor tooling.",
 5 |   "license": "BSD-3-Clause",
 6 |   "repository": {
 7 |     "type": "git",
 8 |     "url": "https://github.com/mdgriffith/elm-dev.git"
 9 |   },
10 |   "homepage": "https://github.com/mdgriffith/elm-dev/tree/master/installers-elm-dev/npm",
11 |   "bugs": "https://github.com/mdgriffith/elm-dev/issues",
12 |   "author": {
13 |     "name": "Matt Griffith",
14 |     "url": "https://github.com/mdgriffith"
15 |   },
16 |   "engines": {
17 |     "node": ">=7.0.0"
18 |   },
19 |   "scripts": {
20 |     "install": "node install.js"
21 |   },
22 |   "files": [
23 |     "install.js",
24 |     "binary.js",
25 |     "bin",
26 |     "bin/elm-dev"
27 |   ],
28 |   "keywords": [
29 |     "bin",
30 |     "binary",
31 |     "binaries",
32 |     "elm",
33 |     "elm-dev",
34 |     "install",
35 |     "installer"
36 |   ],
37 |   "bin": {
38 |     "elm-dev": "bin/elm-dev"
39 |   },
40 |   "optionalDependencies": {
41 |     "@elm_dev_binaries/darwin_arm64": "0.1.3",
42 |     "@elm_dev_binaries/darwin_x64": "0.1.3",
43 |     "@elm_dev_binaries/linux_arm64": "0.1.3",
44 |     "@elm_dev_binaries/linux_x64": "0.1.3",
45 |     "@elm_dev_binaries/win32_x64": "0.1.3"
46 |   }
47 | }
48 | 


--------------------------------------------------------------------------------
/installers-elm-dev/npm/packages/darwin_arm64/README.md:
--------------------------------------------------------------------------------
1 | # Elm Dev Binary for macOS (arm64)
2 | 
3 | Some people install Elm Dev with `npm`. This package helps make [`npm install elm-dev`](https://www.npmjs.com/package/elm-dev) a bit faster and a bit more reliable. It is not intended for direct use!
4 | 
5 | If you do not need to use `npm`, the official binaries are published via [Lamdera](https://static.lamdera.com/bin/elm-dev/).
6 | 


--------------------------------------------------------------------------------
/installers-elm-dev/npm/packages/darwin_arm64/package.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "name": "@elm_dev_binaries/darwin_arm64",
 3 |   "version": "0.1.3",
 4 |   "description": "Download the Elm Dev binary for macOS (arm64)",
 5 |   "repository": "https://github.com/mdgriffith/elm-dev",
 6 |   "license": "BSD-3-Clause",
 7 |   "os": [
 8 |     "darwin"
 9 |   ],
10 |   "cpu": [
11 |     "arm64"
12 |   ]
13 | }
14 | 


--------------------------------------------------------------------------------
/installers-elm-dev/npm/packages/darwin_x64/README.md:
--------------------------------------------------------------------------------
1 | # Elm Dev Binary for macOS (x64)
2 | 
3 | Some people install Elm Dev with `npm`. This package helps make [`npm install elm-dev`](https://www.npmjs.com/package/elm-dev) a bit faster and a bit more reliable. It is not intended for direct use!
4 | 
5 | If you do not need to use `npm`, the official binaries are published via [Lamdera](https://static.lamdera.com/bin/elm-dev/).
6 | 


--------------------------------------------------------------------------------
/installers-elm-dev/npm/packages/darwin_x64/package.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "name": "@elm_dev_binaries/darwin_x64",
 3 |   "version": "0.1.3",
 4 |   "description": "Download the Elm Dev binary for macOS (x64)",
 5 |   "repository": "https://github.com/mdgriffith/elm-dev",
 6 |   "license": "BSD-3-Clause",
 7 |   "os": [
 8 |     "darwin"
 9 |   ],
10 |   "cpu": [
11 |     "x64"
12 |   ]
13 | }
14 | 


--------------------------------------------------------------------------------
/installers-elm-dev/npm/packages/linux_arm64/README.md:
--------------------------------------------------------------------------------
1 | # Elm Dev Binary for Linux (arm64)
2 | 
3 | Some people install Elm Dev with `npm`. This package helps make [`npm install elm-dev`](https://www.npmjs.com/package/elm-dev) a bit faster and a bit more reliable. It is not intended for direct use!
4 | 
5 | If you do not need to use `npm`, the official binaries are published via [Lamdera](https://static.lamdera.com/bin/elm-dev/).
6 | 


--------------------------------------------------------------------------------
/installers-elm-dev/npm/packages/linux_arm64/package.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "name": "@elm_dev_binaries/linux_arm64",
 3 |   "version": "0.1.3",
 4 |   "description": "Download the Elm binary for Linux (arm64)",
 5 |   "repository": "https://github.com/elm/compiler",
 6 |   "license": "BSD-3-Clause",
 7 |   "os": [
 8 |     "linux"
 9 |   ],
10 |   "cpu": [
11 |     "arm64"
12 |   ]
13 | }
14 | 


--------------------------------------------------------------------------------
/installers-elm-dev/npm/packages/linux_x64/README.md:
--------------------------------------------------------------------------------
1 | # Elm Dev Binary for Linux (x64)
2 | 
3 | Some people install Elm Dev with `npm`. This package helps make [`npm install elm-dev`](https://www.npmjs.com/package/elm-dev) a bit faster and a bit more reliable. It is not intended for direct use!
4 | 
5 | If you do not need to use `npm`, the official binaries are published via [Lamdera](https://static.lamdera.com/bin/elm-dev/).
6 | 


--------------------------------------------------------------------------------
/installers-elm-dev/npm/packages/linux_x64/package.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "name": "@elm_dev_binaries/linux_x64",
 3 |   "version": "0.1.3",
 4 |   "description": "Download the Elm Dev binary for Linux (x64)",
 5 |   "repository": "https://github.com/mdgriffith/elm-dev",
 6 |   "license": "BSD-3-Clause",
 7 |   "os": [
 8 |     "linux"
 9 |   ],
10 |   "cpu": [
11 |     "x64"
12 |   ]
13 | }
14 | 


--------------------------------------------------------------------------------
/installers-elm-dev/npm/packages/win32_x64/README.md:
--------------------------------------------------------------------------------
1 | # Elm Dev Binary for Windows (x64)
2 | 
3 | Some people install Elm Dev with `npm`. This package helps make [`npm install elm-dev`](https://www.npmjs.com/package/elm-dev) a bit faster and a bit more reliable. It is not intended for direct use!
4 | 
5 | If you do not need to use `npm`, the official binaries are published via [Lamdera](https://static.lamdera.com/bin/elm-dev/).
6 | 


--------------------------------------------------------------------------------
/installers-elm-dev/npm/packages/win32_x64/package.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "name": "@elm_dev_binaries/win32_x64",
 3 |   "version": "0.1.3",
 4 |   "description": "Download the Elm Dev binary for Windows (x64)",
 5 |   "repository": "https://github.com/mdgriffith/elm-dev",
 6 |   "license": "BSD-3-Clause",
 7 |   "os": [
 8 |     "win32"
 9 |   ],
10 |   "cpu": [
11 |     "x64"
12 |   ]
13 | }
14 | 


--------------------------------------------------------------------------------
/installers/README.md:
--------------------------------------------------------------------------------
 1 | # Installing Elm
 2 | 
 3 | The normal path is to work through [the guide](https://guide.elm-lang.org/) until you need to install, but you can skip to installation directly by going [here](https://guide.elm-lang.org/install/terminal.html).
 4 | 
 5 | 
 6 | 
7 | 8 | ## Installing Multiple Versions 9 | 10 | The secret is that Elm is just a single executable file. If you are developing a project in `~/Desktop/project/` you can download this file into that directory and run commands like `~/Desktop/project/elm make src/Main.elm` or `./elm make src/Main.elm`. You just run the local copy of the executable file! 11 | 12 | The instructions for [Mac][mac] and [Linux][lin] explain how to do this in more detail. You can follow the same steps on Windows, but you need to do each step by hand. (E.g. download the file through your browser rather than with a terminal command.) 13 | 14 | [mac]: https://github.com/elm/compiler/blob/master/installers/mac/README.md 15 | [lin]: https://github.com/elm/compiler/blob/master/installers/linux/README.md 16 | 17 |
18 | 19 | ## Installing Previous Versions 20 | 21 | The past binaries for Mac, Linux, and Windows are hosted [here](https://github.com/elm/compiler/releases). 22 | 23 | You can download the executable files directly and use them locally. 24 | 25 | 26 |
27 | 28 | ## Uninstall 29 | 30 | - [Mac](https://github.com/elm/compiler/blob/master/installers/mac/README.md#uninstall) 31 | - [Linux](https://github.com/elm/compiler/blob/master/installers/linux/README.md#uninstall) 32 | - [Windows](https://github.com/elm/compiler/blob/master/installers/win/README.md#uninstall) 33 | -------------------------------------------------------------------------------- /installers/linux/Dockerfile: -------------------------------------------------------------------------------- 1 | # Based initially on https://gist.github.com/rlefevre/1523f47e75310e28eee243c9c5651ac9 2 | # 3 | # Build Linux x64 binary from elm compiler top-level directory: 4 | # $ docker build -t elm -f installers/linux/Dockerfile . 5 | # 6 | # Retrieve elm Linux binary: 7 | # $ docker cp $(docker create elm):/usr/local/bin/elm DESTINATION_DIRECTORY 8 | # 9 | # Delete docker elm image: 10 | # $ docker rmi elm 11 | # 12 | # Display all images: 13 | # $ docker images -a 14 | # 15 | # Delete all unused docker images: 16 | # $ docker system prune -a 17 | 18 | # Use Alpine 3.11 with GHC 8.6.5 19 | FROM alpine:3.11 20 | 21 | # Install packages required to build elm 22 | RUN apk add --no-cache ghc cabal wget musl-dev zlib-dev zlib-static ncurses-dev ncurses-static 23 | 24 | WORKDIR /elm 25 | 26 | # Import source code 27 | COPY builder builder 28 | COPY compiler compiler 29 | COPY reactor reactor 30 | COPY terminal terminal 31 | COPY cabal.config elm-dev.cabal LICENSE ./ 32 | 33 | # Build statically linked elm binary 34 | RUN cabal new-update 35 | RUN cabal new-build --ghc-option=-optl=-static --ghc-option=-split-sections 36 | RUN cp ./dist-newstyle/build/x86_64-linux/ghc-*/elm-*/x/elm/build/elm/elm /usr/local/bin/elm 37 | 38 | # Remove debug symbols to optimize the binary size 39 | RUN strip -s /usr/local/bin/elm 40 | -------------------------------------------------------------------------------- /installers/mac/Distribution.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Elm 4 | 5 | 6 | 7 | 21 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | binaries.pkg 33 | 34 | -------------------------------------------------------------------------------- /installers/mac/Resources/en.lproj/conclusion.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\cocoartf2509 2 | \cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fmodern\fcharset0 CourierNewPSMT;} 3 | {\colortbl;\red255\green255\blue255;} 4 | {\*\expandedcolortbl;;} 5 | \paperw11900\paperh16840\margl1440\margr1440\vieww11180\viewh8400\viewkind0 6 | \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0 7 | 8 | \f0\fs28 \cf0 Try opening the terminal and running commands like:\ 9 | \ 10 | 11 | \f1 elm init\ 12 | elm make src/Main.elm --optimize\ 13 | elm repl 14 | \f0 \ 15 | \ 16 | Check out {\field{\*\fldinst{HYPERLINK "https://guide.elm-lang.org/"}}{\fldrslt this tutorial}} for more advice!} -------------------------------------------------------------------------------- /installers/mac/Resources/en.lproj/welcome.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\cocoartf2509 2 | \cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fmodern\fcharset0 CourierNewPSMT;} 3 | {\colortbl;\red255\green255\blue255;} 4 | {\*\expandedcolortbl;;} 5 | \paperw11900\paperh16840\margl1440\margr1440\vieww10800\viewh8400\viewkind0 6 | \pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\partightenfactor0 7 | 8 | \f0\fs28 \cf0 Thank you for trying out Elm!\ 9 | \ 10 | This installer makes 11 | \f1 elm 12 | \f0 available in your terminal.} -------------------------------------------------------------------------------- /installers/mac/helper-scripts/elm-startup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | open 'http://guide.elm-lang.org' 4 | -------------------------------------------------------------------------------- /installers/mac/helper-scripts/uninstall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | echo "Warning: You are about to remove all Elm executables!" 6 | 7 | installdir=/usr/local/bin 8 | 9 | for bin in elm elm-compiler elm-get elm-reactor elm-repl elm-doc elm-server elm-package elm-make 10 | do 11 | if [ -f $installdir/$bin ]; then 12 | sudo rm -f $installdir/$bin 13 | fi 14 | if [ -f $installdir/$bin-unwrapped ]; then 15 | sudo rm -f $installdir/$bin-unwrapped 16 | fi 17 | 18 | done 19 | 20 | sharedir=/usr/local/share/elm 21 | sudo rm -rf $sharedir 22 | -------------------------------------------------------------------------------- /installers/mac/postinstall: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -ex 4 | 5 | echo "$(date)" > /tmp/elm-installer.log 6 | -------------------------------------------------------------------------------- /installers/mac/preinstall: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | installdir=/usr/local/bin 6 | 7 | for bin in elm elm-compiler elm-package elm-reactor elm-repl 8 | do 9 | if [ -f $installdir/$bin ]; then 10 | sudo rm -f $installdir/$bin 11 | fi 12 | if [ -f $installdir/$bin-unwrapped ]; then 13 | sudo rm -f $installdir/$bin-unwrapped 14 | fi 15 | done 16 | 17 | sharedir=/usr/local/share/elm 18 | sudo rm -rf $sharedir 19 | -------------------------------------------------------------------------------- /installers/npm/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /installers/npm/.npmignore: -------------------------------------------------------------------------------- 1 | README.md 2 | .gitignore 3 | .git 4 | -------------------------------------------------------------------------------- /installers/npm/PUBLISHING.md: -------------------------------------------------------------------------------- 1 | # Publishing 2 | 3 | Here's how to update the `npm` installer. 4 | 5 | 6 | ## 1. GitHub Release 7 | 8 | Create a [GitHub Release](https://github.com/elm/compiler/releases) with the following files: 9 | 10 | 1. `binary-for-mac-64-bit.gz` 11 | 2. `binary-for-windows-64-bit.gz` 12 | 3. `binary-for-linux-64-bit.gz` 13 | 14 | Create each of these by running the `elm` executable for each platform through `gzip elm`. 15 | 16 | 17 | ## 2. Try a beta release 18 | 19 | In `package.json`, bump the version to `"0.19.2-beta"`. 20 | 21 | ```bash 22 | npm publish --tag beta 23 | ``` 24 | 25 | To test that it works, run these commands: 26 | 27 | ```bash 28 | npm dist-tags ls elm 29 | npm install elm@beta --ignore-scripts 30 | ``` 31 | 32 | The `latest` tag should not be changed, and there should be an additional `beta` tag. 33 | 34 | Try this on Windows, Linux, and Mac. 35 | 36 | 37 | ## 3. Publish final release 38 | 39 | Remove the `-beta` suffix from the version in `package.json`. Then run: 40 | 41 | ```bash 42 | npm publish 43 | ``` 44 | 45 | 46 | ## 4. Tag the `latest-0.19.1` version 47 | 48 | Many compiler releases have needed multiple `npm` publications. Maybe something does not work on Windows or some dependency becomes insecure. Normal `npm` problems. 49 | 50 | The convention for each Elm release is to create a tag the latest one. 51 | 52 | ```bash 53 | npm dist-tag add elm@0.19.1-3 latest-0.19.1 54 | ``` 55 | 56 | That way people who want a specific version can point to `latest-0.19.1` or `latest-0.18.0` instead of knowing the particular names of all the various publications. 57 | 58 | You can read more about dist-tags [here](https://docs.npmjs.com/cli/dist-tag). 59 | 60 | -------------------------------------------------------------------------------- /installers/npm/install.js: -------------------------------------------------------------------------------- 1 | 2 | var download = require('./download.js'); 3 | 4 | download(function() {}); 5 | -------------------------------------------------------------------------------- /installers/npm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "elm", 3 | "version": "0.19.1-5", 4 | "description": "Installer for Elm: just downloads the binary into node_modules", 5 | "preferGlobal": true, 6 | "license": "BSD-3-Clause", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/elm/compiler.git" 10 | }, 11 | "homepage": "https://github.com/elm/compiler/tree/master/installers/npm", 12 | "bugs": "https://github.com/elm/compiler/issues", 13 | "author": { 14 | "name": "Evan Czaplicki", 15 | "email": "evan@elm-lang.org", 16 | "url": "https://github.com/evancz" 17 | }, 18 | "engines": { 19 | "node": ">=7.0.0" 20 | }, 21 | "scripts": { 22 | "install": "node install.js" 23 | }, 24 | "files": [ 25 | "install.js", 26 | "download.js", 27 | "bin", 28 | "bin/elm" 29 | ], 30 | "keywords": [ 31 | "bin", 32 | "binary", 33 | "binaries", 34 | "elm", 35 | "install", 36 | "installer" 37 | ], 38 | "bin": { "elm": "bin/elm" }, 39 | "dependencies": { 40 | "request": "^2.88.0" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /installers/win/CreateInternetShortcut.nsh: -------------------------------------------------------------------------------- 1 | !macro CreateInternetShortcut FILENAME URL ICONFILE ICONINDEX 2 | WriteINIStr "${FILENAME}.url" "InternetShortcut" "URL" "${URL}" 3 | WriteINIStr "${FILENAME}.url" "InternetShortcut" "IconFile" "${ICONFILE}" 4 | WriteINIStr "${FILENAME}.url" "InternetShortcut" "IconIndex" "${ICONINDEX}" 5 | !macroend -------------------------------------------------------------------------------- /installers/win/README.md: -------------------------------------------------------------------------------- 1 | # Installing on Windows 2 | 3 | The installer for Windows is available [here](https://guide.elm-lang.org/install.html). 4 | 5 | 6 |
7 | 8 | ## Uninstall 9 | 10 | First run the `C:\Program Files (x86)\Elm\0.19\uninstall.exe` file. This will remove Elm stuff from your `PATH`. 11 | 12 | Then remove the whole `C:\Users\\AppData\Roaming\elm` directory. Elm caches some packages and build artifacts to reduce compile times and to help you work offline. Getting rid of this directory will clear that information out! 13 | 14 |
15 | 16 | ## Building the Windows installer 17 | 18 | You will need the [NSIS installer](http://nsis.sourceforge.net/Download) to be installed. 19 | 20 | Once everything is installed, run something like this command: 21 | 22 | make_installer.cmd 0.19.0 23 | 24 | It will build an installer called `Elm-0.19.0-setup.exe`. 25 | -------------------------------------------------------------------------------- /installers/win/inst.dat: -------------------------------------------------------------------------------- 1 | SetOutPath "$INSTDIR\bin" 2 | File "${FILES_SOURCE_PATH}\bin\elm.exe" 3 | 4 | SetOutPath "$INSTDIR" 5 | File "updatepath.vbs" 6 | File "removefrompath.vbs" 7 | -------------------------------------------------------------------------------- /installers/win/logo.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/installers/win/logo.ico -------------------------------------------------------------------------------- /installers/win/make_installer.cmd: -------------------------------------------------------------------------------- 1 | 2 | set version=%1 3 | 4 | mkdir files 5 | mkdir files\bin 6 | 7 | xcopy ..\..\dist\build\elm\elm.exe files\bin /s /e 8 | xcopy updatepath.vbs files 9 | 10 | if EXIST "%ProgramFiles%\NSIS" ( 11 | set nsis="%ProgramFiles%\NSIS\makensis.exe" 12 | ) else ( 13 | set nsis="%ProgramFiles(x86)%\NSIS\makensis.exe" 14 | ) 15 | 16 | %nsis% /DPLATFORM_VERSION=%version% Nsisfile.nsi 17 | 18 | rd /s /q files 19 | -------------------------------------------------------------------------------- /installers/win/removefrompath.vbs: -------------------------------------------------------------------------------- 1 | Set WshShell = CreateObject("WScript.Shell") 2 | ' Make sure there is no trailing slash at the end of elmBasePath 3 | elmBasePath = WScript.Arguments(0) 4 | 'const PathRegKey = "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment\Path" 5 | const PathRegKey = "HKCU\Environment\Path" 6 | 7 | on error resume next 8 | path = WshShell.RegRead(PathRegKey) 9 | if err.number = 0 then 10 | Set regEx = New RegExp 11 | elmBasePath = Replace(Replace(Replace(elmBasePath, "\", "\\"), "(", "\("), ")", "\)") 12 | regEx.Pattern = elmBasePath & "\\\d+\.\d+(\.\d+|)\\bin(;|)" 13 | regEx.Global = True 14 | newPath = regEx.Replace(path, "") 15 | Call WshShell.RegWrite(PathRegKey, newPath, "REG_EXPAND_SZ") 16 | end if 17 | on error goto 0 18 | -------------------------------------------------------------------------------- /installers/win/uninst.dat: -------------------------------------------------------------------------------- 1 | Delete "$INSTDIR\bin\elm.exe" 2 | RmDir "$INSTDIR\bin" 3 | 4 | Delete "$INSTDIR\updatepath.vbs" 5 | Delete "$INSTDIR\removefrompath.vbs" 6 | RmDir "$INSTDIR" 7 | -------------------------------------------------------------------------------- /installers/win/updatepath.vbs: -------------------------------------------------------------------------------- 1 | Set WshShell = CreateObject("WScript.Shell") 2 | elmPath = WScript.Arguments(0) 3 | 'const PathRegKey = "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment\Path" 4 | const PathRegKey = "HKCU\Environment\Path" 5 | 6 | on error resume next 7 | path = WshShell.RegRead(PathRegKey) 8 | if err.number <> 0 then 9 | path = "" 10 | end if 11 | on error goto 0 12 | 13 | newPath = elmPath & ";" & path 14 | Call WshShell.RegWrite(PathRegKey, newPath, "REG_EXPAND_SZ") 15 | -------------------------------------------------------------------------------- /installers/win/welcome.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/installers/win/welcome.bmp -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "elm-dev", 3 | "version": "0.1.0", 4 | "description": "Elm tools to support development", 5 | "main": "index.js", 6 | "repository": "https://github.com/mdgriffith/elm-dev.git", 7 | "author": "Matthew Griffith ", 8 | "license": "BSD 3", 9 | "private": true, 10 | "scripts": { 11 | "vscode": "pnpm --cwd apps/vscode", 12 | "watchtower": "stack ghci", 13 | "install:system": "stack install", 14 | "install:vscode": "stack --local-bin-path ./apps/vscode/out install", 15 | "prepare:vscode": "pnpm install:vscode ; (cd apps/vscode ; pnpm package)", 16 | "build": "stack build", 17 | "test-all": "bash scripts/test-project.sh", 18 | "test-generation": "bash scripts/test-generation.sh", 19 | "stack:run": "stack run --" 20 | } 21 | } -------------------------------------------------------------------------------- /reactor/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/reactor/assets/favicon.ico -------------------------------------------------------------------------------- /reactor/assets/source-code-pro.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/reactor/assets/source-code-pro.ttf -------------------------------------------------------------------------------- /reactor/assets/source-sans-pro.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdgriffith/elm-dev/072078a23659f50bada89d2da7c6a5e6926c3349/reactor/assets/source-sans-pro.ttf -------------------------------------------------------------------------------- /reactor/check.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | import sys 5 | 6 | 7 | ## FIGURE OUT NEW MODIFICATION TIME 8 | 9 | def mostRecentModification(directory): 10 | mostRecent = 0 11 | 12 | for dirpath, dirs, files in os.walk(directory): 13 | for f in files: 14 | lastModified = os.path.getmtime(dirpath + '/' + f) 15 | mostRecent = max(int(lastModified), mostRecent) 16 | 17 | return mostRecent 18 | 19 | 20 | srcTime = mostRecentModification('ui/src') 21 | assetTime = mostRecentModification('ui/assets') 22 | mostRecent = max(srcTime, assetTime) 23 | 24 | 25 | ## FIGURE OUT OLD MODIFICATION TIME 26 | 27 | with open('ui/last-modified', 'a') as handle: 28 | pass 29 | 30 | 31 | prevMostRecent = 0 32 | 33 | 34 | with open('ui/last-modified', 'r+') as handle: 35 | line = handle.read() 36 | prevMostRecent = int(line) if line else 0 37 | 38 | 39 | ## TOUCH FILES IF NECESSARY 40 | 41 | if mostRecent > prevMostRecent: 42 | print "+------------------------------------------------------------+" 43 | print "| Some ui/ code changed. Touching src/Reactor/StaticFiles.hs |" 44 | print "| to trigger a recompilation of the Template Haskell stuff. |" 45 | print "+------------------------------------------------------------+" 46 | os.utime('src/Reactor/StaticFiles.hs', None) 47 | with open('ui/last-modified', 'w') as handle: 48 | handle.write(str(mostRecent)) 49 | -------------------------------------------------------------------------------- /reactor/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "src" 5 | ], 6 | "elm-version": "0.19.1", 7 | "dependencies": { 8 | "direct": { 9 | "elm/browser": "1.0.1", 10 | "elm/core": "1.0.2", 11 | "elm/html": "1.0.0", 12 | "elm/http": "2.0.0", 13 | "elm/json": "1.1.2", 14 | "elm/project-metadata-utils": "1.0.0", 15 | "elm/svg": "1.0.1", 16 | "elm-explorations/markdown": "1.0.0" 17 | }, 18 | "indirect": { 19 | "elm/bytes": "1.0.7", 20 | "elm/file": "1.0.1", 21 | "elm/parser": "1.1.0", 22 | "elm/time": "1.0.0", 23 | "elm/url": "1.0.0", 24 | "elm/virtual-dom": "1.0.2" 25 | } 26 | }, 27 | "test-dependencies": { 28 | "direct": {}, 29 | "indirect": {} 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /reactor/src/Index/Navigator.elm: -------------------------------------------------------------------------------- 1 | module Index.Navigator exposing (view) 2 | 3 | 4 | import Html exposing (..) 5 | import Html.Attributes exposing (..) 6 | import Index.Icon as Icon 7 | 8 | 9 | 10 | -- VIEW 11 | 12 | 13 | view : String -> List String -> Html msg 14 | view root dirs = 15 | div 16 | [ style "font-size" "2em" 17 | , style "padding" "20px 0" 18 | , style "display" "flex" 19 | , style "align-items" "center" 20 | , style "height" "40px" 21 | ] 22 | (makeLinks root dirs "" []) 23 | 24 | 25 | makeLinks : String -> List String -> String -> List (Html msg) -> List (Html msg) 26 | makeLinks root dirs oldPath revAnchors = 27 | case dirs of 28 | dir :: otherDirs -> 29 | let 30 | newPath = 31 | oldPath ++ "/" ++ dir 32 | 33 | anchor = 34 | a [ href newPath ] [ text dir ] 35 | in 36 | makeLinks root otherDirs newPath (anchor :: revAnchors) 37 | 38 | [] -> 39 | let 40 | home = 41 | a [ href "/" 42 | , title root 43 | , style "display" "inherit" 44 | ] 45 | [ Icon.home 46 | ] 47 | in 48 | case revAnchors of 49 | [] -> 50 | [home] 51 | 52 | lastAnchor :: otherRevAnchors -> 53 | home :: slash :: List.foldl addSlash [lastAnchor] otherRevAnchors 54 | 55 | 56 | addSlash : Html msg -> List (Html msg) -> List (Html msg) 57 | addSlash front back = 58 | front :: slash :: back 59 | 60 | 61 | slash : Html msg 62 | slash = 63 | span [ style "padding" "0 8px" ] [ text "/" ] 64 | -------------------------------------------------------------------------------- /reactor/src/Index/Skeleton.elm: -------------------------------------------------------------------------------- 1 | module Index.Skeleton exposing 2 | ( box 3 | , readmeBox 4 | ) 5 | 6 | import Html exposing (..) 7 | import Html.Attributes exposing (..) 8 | import Markdown 9 | 10 | import Index.Icon as Icon 11 | 12 | 13 | 14 | -- VIEW BOXES 15 | 16 | 17 | type alias BoxArgs msg = 18 | { title : String 19 | , items : List (List (Html msg)) 20 | , footer : Maybe (String, String) 21 | } 22 | 23 | 24 | box : BoxArgs msg -> Html msg 25 | box { title, items, footer } = 26 | let 27 | realItems = 28 | List.map (div [ class "box-item" ]) items 29 | in 30 | boxHelp title realItems footer 31 | 32 | 33 | readmeBox : String -> Html msg 34 | readmeBox markdown = 35 | let 36 | readme = 37 | Markdown.toHtml [ class "box-item" ] markdown 38 | in 39 | boxHelp "README" [readme] Nothing 40 | 41 | 42 | boxHelp : String -> List (Html msg) -> Maybe (String, String) -> Html msg 43 | boxHelp boxTitle items footer = 44 | div [ class "box" ] <| 45 | div [ class "box-header" ] [ text boxTitle ] 46 | :: items 47 | ++ [ boxFooter footer ] 48 | 49 | 50 | boxFooter : Maybe (String, String) -> Html msg 51 | boxFooter maybeFooter = 52 | case maybeFooter of 53 | Nothing -> 54 | text "" 55 | 56 | Just (path, description) -> 57 | a [ href path 58 | , title description 59 | ] 60 | [ div [ class "box-footer" ] [ Icon.plus ] 61 | ] 62 | -------------------------------------------------------------------------------- /reactor/src/NotFound.elm: -------------------------------------------------------------------------------- 1 | module NotFound exposing (main) 2 | 3 | 4 | import Browser 5 | import Html exposing (..) 6 | import Html.Attributes exposing (..) 7 | 8 | 9 | 10 | main : Program () () () 11 | main = 12 | Browser.document 13 | { init = \_ -> ((), Cmd.none) 14 | , update = \_ _ -> ((), Cmd.none) 15 | , subscriptions = \_ -> Sub.none 16 | , view = \_ -> page 17 | } 18 | 19 | 20 | page : Browser.Document () 21 | page = 22 | { title = "Page not found" 23 | , body = 24 | [ div [ class "not-found" ] 25 | [ div [ style "font-size" "12em" ] [ text "404" ] 26 | , div [ style "font-size" "3em" ] [ text "Page not found" ] 27 | ] 28 | ] 29 | } -------------------------------------------------------------------------------- /reactor/src/mock.txt: -------------------------------------------------------------------------------- 1 | # Dependency Explorer 2 | 3 | Mass Updates: | RESET | PATCH | MINOR | MAJOR | 4 | 5 | ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣇ ←→ 6 | 7 | DEPENDENCIES 8 | 9 | DIRECT 10 | NoRedInk/elm-json-decode-pipeline 1.0.0 → 3.0.0 (MAJOR) 11 | elm/browser 1.0.0 → 1.0.2 (MINOR) 12 | elm/core 1.0.0 → 1.0.5 (CUSTOM: 1.0.0 <= v < 2.0.0) 13 | elm/html 1.0.0 → 6.0.2 (ANY) 14 | elm/http 1.0.0 → 1.0.0 (LOCKED) 15 | elm/json 1.0.0 → 1.0.0 (LOCKED) 16 | elm/time 1.0.0 → 1.0.0 (LOCKED) 17 | elm/url 1.0.0 → 1.0.0 (LOCKED) 18 | elm-explorations/markdown 1.0.0 → 1.0.0 (LOCKED) 19 | rtfeldman/elm-iso8601-date-strings 1.1.0 → (REMOVE) 20 | ADD 21 | 22 | INDIRECT 23 | elm/parser 1.0.0 → 1.0.0 (LOCKED) 24 | elm/virtual-dom 1.0.0 → 1.0.0 (LOCKED) 25 | 26 | TEST DEPENDENCIES 27 | 28 | DIRECT 29 | elm-explorations/test 1.0.0 → 1.0.0 (LOCKED) 30 | ADD 31 | 32 | INDIRECT 33 | elm/random 1.0.0 → 1.0.0 (LOCKED) 34 | -------------------------------------------------------------------------------- /scripts/test-generation.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | 5 | 6 | # Clear the output directory and elm stuff 7 | rm -rf playground 8 | mkdir -p playground 9 | 10 | # Create a new project 11 | stack run --cwd playground -- init 12 | 13 | # Run the generation 14 | stack run --cwd playground -- make elm-stuff/generated/Main.elm 15 | 16 | cd playground 17 | bun install 18 | bun run dev -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | # This defines a function taking `pkgs` as parameter, and uses 2 | # `nixpkgs` by default if no argument is passed to it. 3 | { pkgs ? import { } }: 4 | 5 | # This avoids typing `pkgs.` before each package name. 6 | with pkgs; 7 | 8 | # Defines a shell. 9 | mkShell { 10 | # Sets the build inputs, i.e. what will be available in our 11 | # local environment. 12 | buildInputs = [ 13 | # Basic, typical elm dependencies 14 | elmPackages.elm 15 | elmPackages.elm-format 16 | elmPackages.elm-test-rs 17 | elmPackages.elm-review 18 | # LTS Node 19 | nodejs-18_x 20 | # For the VSCode client 21 | yarn 22 | # Needed for building GHC 23 | llvmPackages_13.llvm 24 | # Other 25 | git 26 | ]; 27 | } 28 | -------------------------------------------------------------------------------- /stack.yaml: -------------------------------------------------------------------------------- 1 | resolver: lts-20.26 # ghc 9.2.8 2 | system-ghc: false 3 | ghc-options: 4 | "$locals": -Wincomplete-patterns -lstdc++ 5 | "$targets": -lstdc++ 6 | allow-newer: true 7 | extra-deps: 8 | - timeout-0.1.1 9 | - command-0.1.1 10 | - snap-server-1.1.2.1 11 | - websockets-snap-0.10.3.1 12 | - fold-debounce-0.2.0.11 13 | - snap-core-1.0.5.1 14 | - readable-0.3.1 15 | - fsnotify-0.4.1.0 16 | 17 | # Required to build on windows 18 | - regex-posix-0.96.0.1 19 | 20 | # windows pinning for build issues 21 | - ansi-terminal-0.11 22 | - git: https://github.com/noteed/language-glsl.git 23 | commit: 99c3aae76363b127679da640a6f00d61d2203830 24 | # Metapackage that apparently resolves below issues for windows: 25 | flags: 26 | regex-posix: 27 | _regex-posix-clib: true 28 | packages: 29 | - '.' 30 | 31 | 32 | # Need to re-check if the below is still an issue now we're on GHC 9.4: 33 | # > The system-cxx-std-lib metapackage should significantly improve the status quo here and is shipped with GHC %9.4.1. Closing. 34 | # --------------- 35 | # https://gitlab.haskell.org/ghc/ghc/-/issues/20010#note_359766 36 | # however extra-libraries is not a supported stack.yaml field...? 37 | # extra-libraries: stdc++ supc++ gcc_s 38 | 39 | # And for windows build issues related to .ddl inclusion 40 | # https://discourse.haskell.org/t/announce-ghcup-0-1-15-rc2-windows-pre-release/2616/14 41 | # however it seems stack automatically includes a bunch of paths, don't think this helped? 42 | # - C:\ghcup\msys64\mingw64\include 43 | -------------------------------------------------------------------------------- /terminal/src/Develop/Socket.hs: -------------------------------------------------------------------------------- 1 | {-# OPTIONS_GHC -Wall #-} 2 | {-# LANGUAGE OverloadedStrings #-} 3 | module Develop.Socket (watchFile) where 4 | 5 | import Control.Concurrent (forkIO, threadDelay) 6 | import Control.Exception (SomeException, catch) 7 | import qualified Data.ByteString.Char8 as BS 8 | import qualified Network.WebSockets as WS 9 | import qualified System.FSNotify.Devel as Notify 10 | import qualified System.FSNotify as Notify 11 | 12 | 13 | 14 | watchFile :: FilePath -> WS.PendingConnection -> IO () 15 | watchFile watchedFile pendingConnection = 16 | do connection <- WS.acceptRequest pendingConnection 17 | 18 | Notify.withManager $ \mgmt -> 19 | do stop <- Notify.treeExtAny mgmt "." ".elm" print 20 | tend connection 21 | stop 22 | 23 | 24 | tend :: WS.Connection -> IO () 25 | tend connection = 26 | let 27 | pinger :: Integer -> IO a 28 | pinger n = 29 | do threadDelay (5 * 1000 * 1000) 30 | WS.sendPing connection (BS.pack (show n)) 31 | pinger (n + 1) 32 | 33 | receiver :: IO () 34 | receiver = 35 | do _ <- WS.receiveDataMessage connection 36 | receiver 37 | 38 | shutdown :: SomeException -> IO () 39 | shutdown _ = 40 | return () 41 | in 42 | do _pid <- forkIO (receiver `catch` shutdown) 43 | pinger 1 `catch` shutdown 44 | -------------------------------------------------------------------------------- /worker/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "src" 5 | ], 6 | "elm-version": "0.19.1", 7 | "dependencies": { 8 | "direct": { 9 | "elm/browser": "1.0.1", 10 | "elm/core": "1.0.2", 11 | "elm/html": "1.0.0", 12 | "elm/json": "1.1.3", 13 | "elm/project-metadata-utils": "1.0.0" 14 | }, 15 | "indirect": { 16 | "elm/parser": "1.1.0", 17 | "elm/time": "1.0.0", 18 | "elm/url": "1.0.0", 19 | "elm/virtual-dom": "1.0.2" 20 | } 21 | }, 22 | "test-dependencies": { 23 | "direct": {}, 24 | "indirect": {} 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /worker/nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name worker.elm-lang.org; 4 | 5 | location / { 6 | proxy_pass http://localhost:8000; 7 | } 8 | } 9 | 10 | server { 11 | listen 443 ssl; 12 | server_name worker.elm-lang.org; 13 | 14 | location / { 15 | proxy_pass http://localhost:8000; 16 | } 17 | 18 | ssl_certificate /etc/letsencrypt/live/worker.elm-lang.org/fullchain.pem; # managed by Certbot 19 | ssl_certificate_key /etc/letsencrypt/live/worker.elm-lang.org/privkey.pem; # managed by Certbot 20 | include /etc/letsencrypt/options-ssl-nginx.conf; 21 | ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; 22 | } 23 | -------------------------------------------------------------------------------- /worker/outlines/compile/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "../../src" 5 | ], 6 | "elm-version": "0.19.1", 7 | "dependencies": { 8 | "direct": { 9 | "elm/browser": "1.0.1", 10 | "elm/core": "1.0.2", 11 | "elm/file": "1.0.5", 12 | "elm/html": "1.0.0", 13 | "elm/http": "2.0.0", 14 | "elm/json": "1.1.3", 15 | "elm/random": "1.0.0", 16 | "elm/svg": "1.0.1", 17 | "elm/time": "1.0.0", 18 | "elm-explorations/linear-algebra": "1.0.3", 19 | "elm-explorations/webgl": "1.1.0", 20 | "evancz/elm-playground": "1.0.2" 21 | }, 22 | "indirect": { 23 | "elm/bytes": "1.0.8", 24 | "elm/url": "1.0.0", 25 | "elm/virtual-dom": "1.0.2" 26 | } 27 | }, 28 | "test-dependencies": { 29 | "direct": {}, 30 | "indirect": {} 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /worker/outlines/repl/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "../../src" 5 | ], 6 | "elm-version": "0.19.1", 7 | "dependencies": { 8 | "direct": { 9 | "elm/core": "1.0.2" 10 | }, 11 | "indirect": { 12 | "elm/json": "1.1.3" 13 | } 14 | }, 15 | "test-dependencies": { 16 | "direct": {}, 17 | "indirect": {} 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /worker/src/Cors.hs: -------------------------------------------------------------------------------- 1 | {-# OPTIONS_GHC -Wall #-} 2 | module Cors 3 | ( allow 4 | ) 5 | where 6 | 7 | 8 | import qualified Data.HashSet as HashSet 9 | import Network.URI (parseURI) 10 | import Snap.Core (Snap, Method, method) 11 | import Snap.Util.CORS (CORSOptions(..), HashableMethod(..), OriginList(Origins), applyCORS, mkOriginSet) 12 | 13 | 14 | 15 | -- ALLOW 16 | 17 | 18 | allow :: Method -> [String] -> Snap () -> Snap () 19 | allow method_ origins snap = 20 | applyCORS (toOptions method_ origins) $ method method_ $ 21 | snap 22 | 23 | 24 | 25 | -- TO OPTIONS 26 | 27 | 28 | toOptions :: (Monad m) => Method -> [String] -> CORSOptions m 29 | toOptions method_ origins = 30 | let 31 | allowedOrigins = toOriginList origins 32 | allowedMethods = HashSet.singleton (HashableMethod method_) 33 | in 34 | CORSOptions 35 | { corsAllowOrigin = return allowedOrigins 36 | , corsAllowCredentials = return True 37 | , corsExposeHeaders = return HashSet.empty 38 | , corsAllowedMethods = return allowedMethods 39 | , corsAllowedHeaders = return 40 | } 41 | 42 | 43 | toOriginList :: [String] -> OriginList 44 | toOriginList origins = 45 | Origins $ mkOriginSet $ 46 | case traverse parseURI origins of 47 | Just uris -> uris 48 | Nothing -> error "invalid entry given to toOriginList list" 49 | --------------------------------------------------------------------------------