├── .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 |
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 |
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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------