├── .envrc ├── .github └── workflows │ ├── ci.yml │ └── deploy_docs.yml ├── .gitignore ├── LICENSE ├── README.md ├── build.zig ├── build.zig.zon ├── examples ├── call_js_from_zig │ ├── index.html │ └── main.zig ├── call_zig_from_js │ ├── index.html │ └── main.zig ├── custom_spa_server_on_free_port │ ├── free_port_web_server.py │ ├── index.html │ ├── main.zig │ └── pages.js ├── custom_web_server │ ├── index.html │ ├── main.zig │ ├── second.html │ └── simple_web_server.py ├── frameless │ ├── index.html │ └── main.zig ├── minimal │ └── main.zig ├── public_network_access │ ├── main.zig │ ├── private.html │ └── public.html ├── serve_a_folder │ ├── bun_test.ts │ ├── deno_test.ts │ ├── dynamic.txt │ ├── index.html │ ├── main.zig │ ├── node_test.js │ ├── second.html │ └── test.txt ├── text_editor │ ├── main.zig │ └── ui │ │ ├── css │ │ ├── all.min.css │ │ ├── codemirror.min.css │ │ ├── lucario.css │ │ └── style.css │ │ ├── img │ │ └── icon.png │ │ ├── index.html │ │ ├── js │ │ ├── clike.min.js │ │ ├── codemirror.min.js │ │ ├── css.min.js │ │ ├── javascript.min.js │ │ ├── python.min.js │ │ ├── ui.js │ │ └── xml.min.js │ │ └── webfonts │ │ ├── fa-brands-400.eot │ │ ├── fa-brands-400.svg │ │ ├── fa-brands-400.ttf │ │ ├── fa-brands-400.woff │ │ ├── fa-brands-400.woff2 │ │ ├── fa-regular-400.eot │ │ ├── fa-regular-400.svg │ │ ├── fa-regular-400.ttf │ │ ├── fa-regular-400.woff │ │ ├── fa-regular-400.woff2 │ │ ├── fa-solid-900.eot │ │ ├── fa-solid-900.svg │ │ ├── fa-solid-900.ttf │ │ ├── fa-solid-900.woff │ │ └── fa-solid-900.woff2 └── web_app_multi_client │ ├── index.html │ └── main.zig ├── flake.lock ├── flake.nix └── src ├── c.zig └── webui.zig /.envrc: -------------------------------------------------------------------------------- 1 | use flake 2 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | # http://webui.me 2 | # https://github.com/webui-dev/zig-webui 3 | # Licensed under MIT License. 4 | # All rights reserved. 5 | 6 | name: CI 7 | on: 8 | push: 9 | paths: 10 | - "**.zig" 11 | pull_request: 12 | branches: [main] 13 | paths: 14 | - "**.zig" 15 | schedule: 16 | - cron: "0 2 * * *" 17 | jobs: 18 | build: 19 | strategy: 20 | matrix: 21 | os: [ubuntu-latest, macos-latest, windows-latest] 22 | version: [0.14.0, ""] 23 | fail-fast: false 24 | runs-on: ${{ matrix.os }} 25 | steps: 26 | - uses: maxim-lobanov/setup-xcode@v1 27 | if: runner.os == 'macOS' 28 | with: 29 | xcode-version: latest-stable 30 | - name: Setup Zig 31 | uses: goto-bus-stop/setup-zig@v2 32 | with: 33 | version: ${{ matrix.version }} 34 | - uses: actions/checkout@v4 35 | - name: Build examples 36 | run: zig build examples 37 | - name: Build examples dynamic 38 | if: runner.os != 'Windows' 39 | run: zig build examples -Dis_static=false 40 | lint: 41 | runs-on: ubuntu-latest 42 | steps: 43 | - name: Setup Zig 44 | uses: goto-bus-stop/setup-zig@v2 45 | - name: Verify formatting 46 | run: zig fmt . 47 | -------------------------------------------------------------------------------- /.github/workflows/deploy_docs.yml: -------------------------------------------------------------------------------- 1 | # http://webui.me 2 | # https://github.com/webui-dev/zig-webui 3 | # Licensed under MIT License. 4 | # All rights reserved. 5 | 6 | name: DeployDocs 7 | 8 | on: 9 | push: 10 | branches: [main] 11 | 12 | # Allows you to run this workflow manually from the Actions tab 13 | workflow_dispatch: 14 | inputs: 15 | logLevel: 16 | description: "Log level" 17 | required: true 18 | default: "warning" 19 | tags: 20 | description: "deploy docs" 21 | 22 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 23 | permissions: 24 | contents: write 25 | pages: write 26 | id-token: write 27 | 28 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. 29 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. 30 | concurrency: 31 | group: pages 32 | cancel-in-progress: false 33 | 34 | jobs: 35 | # Build job 36 | build: 37 | runs-on: ubuntu-latest 38 | steps: 39 | - name: Checkout 40 | uses: actions/checkout@v3 41 | with: 42 | fetch-depth: 0 # Not needed if lastUpdated is not enabled 43 | - uses: goto-bus-stop/setup-zig@v2 44 | - name: remove ./src/examples 45 | run: rm -rf ./src/examples 46 | - name: Generate Docs 47 | run: zig build docs 48 | - name: Upload artifact 49 | uses: actions/upload-pages-artifact@v3 50 | with: 51 | path: ./zig-out/docs 52 | deploy: 53 | environment: 54 | name: github-pages 55 | url: ${{ steps.deployment.outputs.page_url }} 56 | runs-on: ubuntu-latest 57 | needs: build 58 | steps: 59 | - name: Deploy to GitHub Pages 60 | id: deployment 61 | uses: actions/deploy-pages@v4 62 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | zig-cache 2 | zig-out 3 | .direnv 4 | .zig-cache 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 WebUI 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | ![Logo](https://raw.githubusercontent.com/webui-dev/webui-logo/main/webui_zig.png) 4 | 5 | # WebUI Zig v2.5.0-beta.4 6 | 7 | 8 | 9 | [last-commit]: https://img.shields.io/github/last-commit/webui-dev/zig-webui?style=for-the-badge&logo=github&logoColor=C0CAF5&labelColor=414868 10 | 11 | [license]: https://img.shields.io/github/license/webui-dev/zig-webui?style=for-the-badge&logo=opensourcehardware&label=License&logoColor=C0CAF5&labelColor=414868&color=8c73cc 12 | 13 | 14 | 15 | [![][last-commit]](https://github.com/webui-dev/zig-webui/pulse) 16 | 17 | [![][license]](https://github.com/webui-dev/zig-webui/blob/main/LICENSE) 18 | 19 | > Use any web browser or WebView as GUI, with Zig in the backend and modern web technologies in the frontend, all in a lightweight portable library. 20 | 21 | ![Screenshot](https://raw.githubusercontent.com/webui-dev/webui-logo/main/screenshot.png) 22 | 23 |
24 | 25 | ## Features 26 | 27 | - Portable (*Needs only a web browser or a WebView at runtime*) 28 | - One header file 29 | - Lightweight (*Few Kb library*) & Small memory footprint 30 | - Fast binary communication protocol 31 | - Multi-platform & Multi-Browser 32 | - Using private profile for safety 33 | - Cross-platform WebView 34 | 35 | ## API Documentation 36 | 37 | If you want a clearer architecture, you can check it out [here](https://deepwiki.com/webui-dev/zig-webui) 38 | 39 | * [https://webui-dev.github.io/zig-webui/](https://webui-dev.github.io/zig-webui/) 40 | * [https://webui.me/docs/2.5/#/](https://webui.me/docs/2.5/#/) 41 | 42 | ## Examples 43 | 44 | There are several examples for newbies, they are in the `examples` directory. 45 | 46 | You can use `zig build --help` to view all buildable examples. 47 | 48 | Like `zig build run_minimal`, this will build and run the `minimal` example. 49 | 50 | ## Installation 51 | 52 | > note: for `0.13.0` and previous version, please use tag `2.5.0-beta.2` 53 | 54 | ### Zig `0.14.0` \ `nightly` 55 | 56 | > To be honest, I don’t recommend using the nightly version because the API of the build system is not yet stable, which means that there may be problems with not being able to build after nightly is updated. 57 | 58 | 1. Add to `build.zig.zon` 59 | 60 | ```sh 61 | # It is recommended to replace the following branch with commit id 62 | zig fetch --save https://github.com/webui-dev/zig-webui/archive/main.tar.gz 63 | # Of course, you can also use git+https to fetch this package! 64 | ``` 65 | 66 | 2. Config `build.zig` 67 | 68 | Add this: 69 | 70 | ```zig 71 | // To standardize development, maybe you should use `lazyDependency()` instead of `dependency()` 72 | // more info to see: https://ziglang.org/download/0.12.0/release-notes.html#toc-Lazy-Dependencies 73 | const zig_webui = b.dependency("zig_webui", .{ 74 | .target = target, 75 | .optimize = optimize, 76 | .enable_tls = false, // whether enable tls support 77 | .is_static = true, // whether static link 78 | }); 79 | 80 | // add module 81 | exe.root_module.addImport("webui", zig_webui.module("webui")); 82 | ``` 83 | 84 | > It is not recommended to dynamically link libraries under Windows, which may cause some symbol duplication problems. 85 | > see this issue: https://github.com/ziglang/zig/issues/15107 86 | 87 | ### Windows without console 88 | 89 | For hide console window, you can set `exe.subsystem = .Windows;`! 90 | 91 | ## UI & The Web Technologies 92 | 93 | [Borislav Stanimirov](https://ibob.bg/) discusses using HTML5 in the web browser as GUI at the [C++ Conference 2019 (_YouTube_)](https://www.youtube.com/watch?v=bbbcZd4cuxg). 94 | 95 | 98 | 99 |
100 | 101 | ![CPPCon](https://github.com/webui-dev/webui/assets/34311583/4e830caa-4ca0-44ff-825f-7cd6d94083c8) 102 | 103 |
104 | 105 | Web application UI design is not just about how a product looks but how it works. Using web technologies in your UI makes your product modern and professional, And a well-designed web application will help you make a solid first impression on potential customers. Great web application design also assists you in nurturing leads and increasing conversions. In addition, it makes navigating and using your web app easier for your users. 106 | 107 | ### Why Use Web Browsers? 108 | 109 | Today's web browsers have everything a modern UI needs. Web browsers are very sophisticated and optimized. Therefore, using it as a GUI will be an excellent choice. While old legacy GUI lib is complex and outdated, a WebView-based app is still an option. However, a WebView needs a huge SDK to build and many dependencies to run, and it can only provide some features like a real web browser. That is why WebUI uses real web browsers to give you full features of comprehensive web technologies while keeping your software lightweight and portable. 110 | 111 | ### How Does it Work? 112 | 113 |
114 | 115 | ![Diagram](https://github.com/ttytm/webui/assets/34311583/dbde3573-3161-421e-925c-392a39f45ab3) 116 | 117 |
118 | 119 | Think of WebUI like a WebView controller, but instead of embedding the WebView controller in your program, which makes the final program big in size, and non-portable as it needs the WebView runtimes. Instead, by using WebUI, you use a tiny static/dynamic library to run any installed web browser and use it as GUI, which makes your program small, fast, and portable. **All it needs is a web browser**. 120 | 121 | ### Runtime Dependencies Comparison 122 | 123 | | | Tauri / WebView | Qt | WebUI | 124 | | ------------------------------- | ----------------- | -------------------------- | ------------------- | 125 | | Runtime Dependencies on Windows | _WebView2_ | _QtCore, QtGui, QtWidgets_ | **_A Web Browser_** | 126 | | Runtime Dependencies on Linux | _GTK3, WebKitGTK_ | _QtCore, QtGui, QtWidgets_ | **_A Web Browser_** | 127 | | Runtime Dependencies on macOS | _Cocoa, WebKit_ | _QtCore, QtGui, QtWidgets_ | **_A Web Browser_** | 128 | 129 | ## Supported Web Browsers 130 | 131 | | Browser | Windows | macOS | Linux | 132 | | --------------- | --------------- | ------------- | --------------- | 133 | | Mozilla Firefox | ✔️ | ✔️ | ✔️ | 134 | | Google Chrome | ✔️ | ✔️ | ✔️ | 135 | | Microsoft Edge | ✔️ | ✔️ | ✔️ | 136 | | Chromium | ✔️ | ✔️ | ✔️ | 137 | | Yandex | ✔️ | ✔️ | ✔️ | 138 | | Brave | ✔️ | ✔️ | ✔️ | 139 | | Vivaldi | ✔️ | ✔️ | ✔️ | 140 | | Epic | ✔️ | ✔️ | _not available_ | 141 | | Apple Safari | _not available_ | _coming soon_ | _not available_ | 142 | | Opera | _coming soon_ | _coming soon_ | _coming soon_ | 143 | 144 | ## Supported WebView 145 | 146 | | WebView | Status | 147 | | --------------- | --------------- | 148 | | Windows WebView2 | ✔️ | 149 | | Linux GTK WebView | ✔️ | 150 | | macOS WKWebView | ✔️ | 151 | 152 | ### License 153 | 154 | > Licensed under the MIT License. 155 | -------------------------------------------------------------------------------- /build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const builtin = @import("builtin"); 3 | 4 | const Build = std.Build; 5 | 6 | // Minimum required Zig version for this project 7 | const min_zig_string = "0.12.0"; 8 | const current_zig = builtin.zig_version; 9 | 10 | // NOTE: we should note that when enable tls support we cannot compile with musl 11 | 12 | // Compile-time check to ensure the Zig version meets the minimum requirement 13 | comptime { 14 | const min_zig = std.SemanticVersion.parse(min_zig_string) catch unreachable; 15 | if (current_zig.order(min_zig) == .lt) { 16 | @compileError(std.fmt.comptimePrint("Your Zig version v{} does not meet the minimum build requirement of v{}", .{ current_zig, min_zig })); 17 | } 18 | } 19 | 20 | // Define logger and useful type aliases 21 | const log = std.log.scoped(.WebUI); 22 | const OptimizeMode = std.builtin.OptimizeMode; 23 | const CrossTarget = std.Target.Query; 24 | const Compile = Build.Step.Compile; 25 | const Module = Build.Module; 26 | 27 | // Default build configuration options 28 | const default_isStatic = true; 29 | const default_enableTLS = false; 30 | 31 | pub fn build(b: *Build) !void { 32 | // Parse command-line options or use defaults 33 | const isStatic = b.option(bool, "is_static", "whether lib is static") orelse default_isStatic; 34 | const enableTLS = b.option(bool, "enable_tls", "whether lib enable tls") orelse default_enableTLS; 35 | 36 | // Standard build options for target and optimization 37 | const target = b.standardTargetOptions(.{}); 38 | const optimize = b.standardOptimizeOption(.{}); 39 | 40 | // TLS support has some limitations 41 | if (enableTLS) { 42 | log.info("enable TLS support", .{}); 43 | if (!target.query.isNative()) { 44 | log.info("when enable tls, not support cross compile", .{}); 45 | std.posix.exit(1); 46 | } 47 | } 48 | 49 | // Create build options that will be used as a module 50 | const flags_options = b.addOptions(); 51 | 52 | // Configure compile-time options 53 | flags_options.addOption(bool, "enableTLS", enableTLS); 54 | 55 | // Create a module that exposes the options 56 | const flags_module = flags_options.createModule(); 57 | 58 | // Get the webui dependency with appropriate options 59 | const webui = b.dependency("webui", .{ 60 | .target = target, 61 | .optimize = optimize, 62 | .dynamic = !isStatic, 63 | .@"enable-tls" = enableTLS, 64 | .verbose = .err, 65 | }); 66 | 67 | // Create the webui module that applications can import 68 | const webui_module = b.addModule("webui", .{ 69 | .root_source_file = b.path(b.pathJoin(&.{ "src", "webui.zig" })), 70 | .imports = &.{ 71 | .{ 72 | .name = "flags", 73 | .module = flags_module, 74 | }, 75 | }, 76 | }); 77 | // Link against the webui library 78 | webui_module.linkLibrary(webui.artifact("webui")); 79 | if (!isStatic) { 80 | // For dynamic libraries, install the shared library 81 | b.installArtifact(webui.artifact("webui")); 82 | } 83 | 84 | // Setup documentation generation 85 | generate_docs(b, optimize, target, flags_module); 86 | 87 | // Build example applications 88 | build_examples(b, optimize, target, webui_module, webui.artifact("webui")) catch |err| { 89 | log.err("failed to build examples: {}", .{err}); 90 | std.process.exit(1); 91 | }; 92 | } 93 | 94 | // Function to generate API documentation 95 | fn generate_docs(b: *Build, optimize: OptimizeMode, target: Build.ResolvedTarget, flags_module: *Module) void { 96 | // Create a temporary object for documentation generation 97 | const webui_lib = b.addObject(.{ 98 | .name = "webui_lib", 99 | .root_source_file = b.path(b.pathJoin(&.{ "src", "webui.zig" })), 100 | .target = target, 101 | .optimize = optimize, 102 | }); 103 | 104 | webui_lib.root_module.addImport("flags", flags_module); 105 | 106 | // Create a build step for documentation 107 | const docs_step = b.step("docs", "Generate docs"); 108 | 109 | // Setup documentation installation 110 | const docs_install = b.addInstallDirectory(.{ 111 | .source_dir = webui_lib.getEmittedDocs(), 112 | .install_dir = .prefix, 113 | .install_subdir = "docs", 114 | }); 115 | 116 | docs_step.dependOn(&docs_install.step); 117 | } 118 | 119 | // Function to build all example applications 120 | fn build_examples(b: *Build, optimize: OptimizeMode, target: Build.ResolvedTarget, webui_module: *Module, webui_lib: *Compile) !void { 121 | 122 | // Get the absolute path to the examples directory 123 | var lazy_path = b.path("examples"); 124 | 125 | // Create a step to build all examples 126 | const build_all_step = b.step("examples", "build all examples"); 127 | 128 | const examples_path = lazy_path.getPath(b); 129 | 130 | // Open the examples directory for iteration 131 | var iter_dir = std.fs.openDirAbsolute( 132 | examples_path, 133 | .{ .iterate = true }, 134 | ) catch |err| { 135 | switch (err) { 136 | error.FileNotFound => return, 137 | else => return err, 138 | } 139 | }; 140 | defer iter_dir.close(); 141 | 142 | var itera = iter_dir.iterate(); 143 | 144 | // Iterate through all subdirectories in the examples directory 145 | while (try itera.next()) |val| { 146 | if (val.kind != .directory) { 147 | continue; 148 | } 149 | 150 | const example_name = val.name; 151 | const path = b.pathJoin(&.{ "examples", example_name, "main.zig" }); 152 | 153 | // Create an executable for each example 154 | const exe = b.addExecutable(.{ 155 | .name = example_name, 156 | .root_source_file = b.path(path), 157 | .target = target, 158 | .optimize = optimize, 159 | }); 160 | 161 | // Add the webui module and link against the library 162 | exe.root_module.addImport("webui", webui_module); 163 | exe.linkLibrary(webui_lib); 164 | 165 | // Setup installation 166 | const exe_install = b.addInstallArtifact(exe, .{}); 167 | 168 | build_all_step.dependOn(&exe_install.step); 169 | 170 | // Create a run step for the example 171 | const exe_run = b.addRunArtifact(exe); 172 | exe_run.step.dependOn(&exe_install.step); 173 | 174 | // Set the working directory for the run 175 | const cwd = b.path(b.pathJoin(&.{ "examples", example_name })); 176 | exe_run.setCwd(cwd); 177 | 178 | // Create a named step to run this specific example 179 | const step_name = try std.fmt.allocPrint(b.allocator, "run_{s}", .{example_name}); 180 | const step_desc = try std.fmt.allocPrint(b.allocator, "run_{s}", .{example_name}); 181 | 182 | const exe_run_step = b.step(step_name, step_desc); 183 | exe_run_step.dependOn(&exe_run.step); 184 | } 185 | } 186 | 187 | -------------------------------------------------------------------------------- /build.zig.zon: -------------------------------------------------------------------------------- 1 | .{ 2 | .name = .zig_webui, 3 | .version = "2.5.0-beta.4", 4 | .fingerprint = 0x95965ed3cdfb8c33, 5 | .minimum_zig_version = "0.14.0", 6 | .dependencies = .{ 7 | .webui = .{ 8 | .hash = "webui-2.5.0-beta.4-pxqD5esSNwCHzwq6ndnW-ShzC_nPNAzGu13l4Unk0rFl", 9 | .url = "https://github.com/webui-dev/webui/archive/699119f42fc64ae42c9121bc4749b740f71949af.tar.gz", 10 | }, 11 | }, 12 | .paths = .{ 13 | "build.zig", 14 | "build.zig.zon", 15 | "src", 16 | }, 17 | } 18 | -------------------------------------------------------------------------------- /examples/call_js_from_zig/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Call JavaScript from Zig Example 7 | 46 | 47 | 48 |

WebUI - Call JavaScript from Zig

49 |
50 |

0

51 |
52 | 53 |
54 | 57 |
58 | 59 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /examples/call_js_from_zig/main.zig: -------------------------------------------------------------------------------- 1 | //! Call JavaScript from Zig Example 2 | const std = @import("std"); 3 | const webui = @import("webui"); 4 | const html = @embedFile("index.html"); 5 | 6 | pub fn main() !void { 7 | // Create a window 8 | var nwin = webui.newWindow(); 9 | 10 | // Bind HTML elements with C functions 11 | _ = try nwin.bind("my_function_count", my_function_count); 12 | _ = try nwin.bind("my_function_exit", my_function_exit); 13 | 14 | // Show the window 15 | try nwin.show(html); 16 | // _ = nwin.showBrowser(html, .Chrome); 17 | 18 | // Wait until all windows get closed 19 | webui.wait(); 20 | 21 | // Free all memory resources (Optional) 22 | webui.clean(); 23 | } 24 | 25 | fn my_function_count(e: *webui.Event) void { 26 | // This function gets called every time the user clicks on "my_function_count" 27 | 28 | // Create a buffer to hold the response 29 | var response = std.mem.zeroes([64]u8); 30 | 31 | const win = e.getWindow(); 32 | 33 | // Run JavaScript 34 | win.script("return GetCount();", 0, &response) catch { 35 | if (!win.isShown()) { 36 | std.debug.print("window closed\n", .{}); 37 | } else { 38 | std.debug.print("js error:{s}\n", .{response}); 39 | } 40 | }; 41 | 42 | const res_buf = response[0..std.mem.len(@as([*:0]u8, @ptrCast(&response)))]; 43 | 44 | // Get the count 45 | var tmp_count = std.fmt.parseInt(i32, res_buf, 10) catch |err| blk: { 46 | std.log.err("error is {}", .{err}); 47 | break :blk -50; 48 | }; 49 | 50 | // Increment 51 | tmp_count += 1; 52 | 53 | // Generate a JavaScript 54 | var js: [64]u8 = std.mem.zeroes([64]u8); 55 | const buf = std.fmt.bufPrint(&js, "SetCount({});", .{tmp_count}) catch unreachable; 56 | 57 | // convert to a Sentinel-Terminated slice 58 | const content: [:0]const u8 = js[0..buf.len :0]; 59 | 60 | // Run JavaScript (Quick Way) 61 | win.run(content); 62 | } 63 | 64 | fn my_function_exit(_: *webui.Event) void { 65 | 66 | // Close all opened windows 67 | webui.exit(); 68 | } 69 | -------------------------------------------------------------------------------- /examples/call_zig_from_js/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Call Zig from JavaScript Example 7 | 41 | 42 | 43 |

WebUI - Call Zig from JavaScript

44 |

45 | Call C functions with arguments (See the logs in your terminal) 46 |

47 | 50 | 53 |
54 | 57 |
58 | 63 |
64 |

Call a C function that returns a response

65 | 66 |
Double:
67 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /examples/call_zig_from_js/main.zig: -------------------------------------------------------------------------------- 1 | //! Call Zig from JavaScript Example 2 | const std = @import("std"); 3 | const webui = @import("webui"); 4 | 5 | // we use @embedFile to embed html 6 | const html = @embedFile("index.html"); 7 | 8 | pub fn main() !void { 9 | // Create a new WebUI window object 10 | var nwin = webui.newWindow(); 11 | 12 | // Use binding function instead of standard bind function 13 | // binding is an advanced API that automatically handles parameter type conversion and function signature adaptation 14 | // It allows using native Zig function signatures without needing to handle Event pointers directly 15 | // Here we bind the HTML/JS "my_function_string" to Zig function getString 16 | _ = try nwin.binding("my_function_string", getString); 17 | // Equivalent using traditional bind function which requires manual Event handling 18 | // _ = try nwin.bind("my_function_string", my_function_string); 19 | 20 | // Bind integer handler function, binding automatically converts JS parameters to corresponding Zig types 21 | _ = try nwin.binding("my_function_integer", getInteger); 22 | // _ = try nwin.bind("my_function_integer", my_function_integer); 23 | 24 | // Bind boolean handler function, also with automatic type conversion 25 | _ = try nwin.binding("my_function_boolean", getBool); 26 | // _ = try nwin.bind("my_function_boolean", my_function_boolean); 27 | 28 | // Bind function with response, binding supports using event object directly for responses 29 | _ = try nwin.binding("my_function_with_response", getResponse); 30 | // _ = try nwin.bind("my_function_with_response", my_function_with_response); 31 | 32 | // Bind function for handling binary data, binding supports raw binary data processing 33 | _ = try nwin.binding("my_function_raw_binary", raw_binary); 34 | // _ = try nwin.bind("my_function_raw_binary", my_function_raw_binary); 35 | 36 | // Show the window with embedded HTML content 37 | try nwin.show(html); 38 | 39 | // Wait for all windows to close, this will block the current thread 40 | webui.wait(); 41 | 42 | // Clean up all resources 43 | webui.clean(); 44 | } 45 | 46 | fn getString(str1: [:0]const u8, str2: [:0]const u8) void { 47 | // Hello 48 | std.debug.print("my_function_string 1: {s}\n", .{str1}); 49 | // World 50 | std.debug.print("my_function_string 2: {s}\n", .{str2}); 51 | } 52 | 53 | fn my_function_string(e: *webui.Event) void { 54 | // JavaScript: 55 | // my_function_string('Hello', 'World`); 56 | 57 | // or e.getStringAt(0); 58 | const str_1 = e.getString(); 59 | const str_2 = e.getStringAt(1); 60 | 61 | // Hello 62 | std.debug.print("my_function_string 1: {s}\n", .{str_1}); 63 | // World 64 | std.debug.print("my_function_string 2: {s}\n", .{str_2}); 65 | } 66 | 67 | fn getInteger(n1: i64, n2: i64, n3: i64, f1: f64) void { 68 | std.debug.print("number is {},{},{},{}", .{ 69 | n1, n2, n3, f1, 70 | }); 71 | } 72 | 73 | fn my_function_integer(e: *webui.Event) void { 74 | // JavaScript: 75 | // my_function_integer(123, 456, 789, 12345.6789); 76 | 77 | const count = e.getCount(); 78 | 79 | std.debug.print("my_function_integer: There is {} arguments in this event\n", .{count}); 80 | 81 | // Or e.getIntAt(0); 82 | const number_1 = e.getInt(); 83 | const number_2 = e.getIntAt(1); 84 | const number_3 = e.getIntAt(2); 85 | 86 | // 123 87 | std.debug.print("my_function_integer 1: {}\n", .{number_1}); 88 | // 456 89 | std.debug.print("my_function_integer 2: {}\n", .{number_2}); 90 | // 789 91 | std.debug.print("my_function_integer 3: {}\n", .{number_3}); 92 | 93 | const float_1 = e.getFloatAt(3); 94 | // 12345.6789 95 | std.debug.print("my_function_integer 4: {}\n", .{float_1}); 96 | } 97 | 98 | fn getBool(b1: bool, b2: bool) void { 99 | std.debug.print("boolean is {},{}", .{ 100 | b1, b2, 101 | }); 102 | } 103 | 104 | fn my_function_boolean(e: *webui.Event) void { 105 | // JavaScript: 106 | // my_function_boolean(true, false); 107 | 108 | // Or e.getBoolAt(0); 109 | const status_1 = e.getBool(); 110 | const status_2 = e.getBoolAt(1); 111 | 112 | // Ture 113 | std.debug.print("my_function_bool 1: {}\n", .{status_1}); 114 | // False 115 | std.debug.print("my_function_bool 2: {}\n", .{status_2}); 116 | } 117 | 118 | fn getResponse(e: *webui.Event,n1: i64, n2: i64) void { 119 | const res = n1 * n2; 120 | std.debug.print("my_function_with_response: {} * {} = {}\n", .{ n1, n2, res }); 121 | // Send back the response to JavaScript 122 | e.returnValue(res); 123 | } 124 | 125 | fn my_function_with_response(e: *webui.Event) void { 126 | // JavaScript: 127 | // my_function_with_response(number, 2).then(...) 128 | 129 | // Or e.getIntAt(0); 130 | const number = e.getInt(); 131 | const times = e.getIntAt(1); 132 | const res = number * times; 133 | 134 | std.debug.print("my_function_with_response: {} * {} = {}\n", .{ number, times, res }); 135 | 136 | // Send back the response to JavaScript 137 | e.returnValue(res); 138 | } 139 | 140 | fn raw_binary(e: *webui.Event, raw_1: [:0]const u8, raw_2: [*]const u8) void { 141 | // Or e.getSizeAt(0); 142 | const len_1 = e.getSize() catch return; 143 | const len_2 = e.getSizeAt(1) catch return; 144 | 145 | // Print raw_1 146 | std.debug.print("my_function_raw_binary 1 ({} bytes): ", .{len_1}); 147 | for (0..len_1) |i| { 148 | std.debug.print("0x{x} ", .{raw_1[i]}); 149 | } 150 | std.debug.print("\n", .{}); 151 | 152 | // Check raw_2 (Big) 153 | // [0xA1, 0x00..., 0xA2] 154 | var vaild = false; 155 | 156 | if (raw_2[0] == 0xA1 and raw_2[len_2 - 1] == 0xA2) { 157 | vaild = true; 158 | } 159 | 160 | // Print raw_2 161 | std.debug.print("my_function_raw_binary 2 big ({} bytes): valid data? {s}\n", .{ 162 | len_2, 163 | if (vaild) "Yes" else "No", 164 | }); 165 | } 166 | 167 | fn my_function_raw_binary(e: *webui.Event) void { 168 | // JavaScript: 169 | // my_function_raw_binary(new Uint8Array([0x41]), new Uint8Array([0x42, 0x43])); 170 | 171 | // Or e.getStringAt(0); 172 | const raw_1 = e.getString(); 173 | const raw_2 = e.getRawAt(1); 174 | 175 | // Or e.getSizeAt(0); 176 | const len_1 = e.getSize() catch return; 177 | const len_2 = e.getSizeAt(1) catch return; 178 | 179 | // Print raw_1 180 | std.debug.print("my_function_raw_binary 1 ({} bytes): ", .{len_1}); 181 | for (0..len_1) |i| { 182 | std.debug.print("0x{x} ", .{raw_1[i]}); 183 | } 184 | std.debug.print("\n", .{}); 185 | 186 | // Check raw_2 (Big) 187 | // [0xA1, 0x00..., 0xA2] 188 | var vaild = false; 189 | 190 | if (raw_2[0] == 0xA1 and raw_2[len_2 - 1] == 0xA2) { 191 | vaild = true; 192 | } 193 | 194 | // Print raw_2 195 | std.debug.print("my_function_raw_binary 2 big ({} bytes): valid data? {s}\n", .{ 196 | len_2, 197 | if (vaild) "Yes" else "No", 198 | }); 199 | } 200 | -------------------------------------------------------------------------------- /examples/custom_spa_server_on_free_port/free_port_web_server.py: -------------------------------------------------------------------------------- 1 | import http.server 2 | from http.server import BaseHTTPRequestHandler 3 | import socketserver 4 | import sys 5 | 6 | SERVER_PORT_STR = sys.argv[1] 7 | SERVER_PORT = int(SERVER_PORT_STR) 8 | 9 | WEBUI_PORT_STR = sys.argv[2] 10 | 11 | class MyHandler(BaseHTTPRequestHandler): 12 | def do_GET(self): 13 | try: 14 | f = open("." + self.path) 15 | content = f.read() 16 | self.send_response(200) 17 | if (self.path.endswith(".html")): 18 | self.send_header('Content-type','text/html') 19 | # now set webui port 20 | content = content.replace("[WEBUI_PORT]", WEBUI_PORT_STR) 21 | if (self.path.endswith(".js")): 22 | self.send_header('Content-type','text/javascript') 23 | self.send_header('cache-control', 'no-cache') 24 | self.end_headers() 25 | self.wfile.write(content.encode()) 26 | f.close() 27 | return 28 | except IOError: 29 | self.send_error(404,'File Not Found: %s' % self.path) 30 | 31 | with socketserver.TCPServer(("", SERVER_PORT), MyHandler) as httpd: 32 | print(f"Server started at http://localhost:{SERVER_PORT_STR}") 33 | httpd.serve_forever() 34 | -------------------------------------------------------------------------------- /examples/custom_spa_server_on_free_port/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WebUI - Custom Web-Server Free Port Example (C) 7 | 8 | 9 | 10 | 16 | 17 | 18 |
19 |
20 |

Home

21 | 22 | 23 | 29 |
30 |
31 |
32 |
33 |

This is the First (Home) Page

34 |
35 |
36 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /examples/custom_spa_server_on_free_port/main.zig: -------------------------------------------------------------------------------- 1 | //! Custom web Server - Free Port - Example 2 | // Note: if you want to run this example, you nedd a python, zig will wrap a child process to launch python server 3 | const std = @import("std"); 4 | const webui = @import("webui"); 5 | 6 | var python_server_proc: std.process.Child = undefined; 7 | var python_running: bool = false; 8 | 9 | var home_url: [:0]u8 = undefined; 10 | 11 | pub fn main() !void { 12 | // Create new window 13 | var nwin = webui.newWindow(); 14 | 15 | // Bind all events 16 | _ = try nwin.bind("", events); 17 | // Bind a JS call to a Zig fn 18 | _ = try nwin.bind("gotoPage", goto_page); 19 | 20 | // The `webui.js` script will be available at: 21 | // 22 | // http://localhost:[WEBUI_PORT]/webui.js 23 | // 24 | // (see [WEBUI_PORT] in: index.html, free_port_web_server.py) 25 | // 26 | // So, get and set a free port for WebUI to use: 27 | 28 | const webui_port: u64 = webui.getFreePort(); 29 | std.debug.print("Free Port for webui.js: {d} \n", .{webui_port}); 30 | // now use the port: 31 | try nwin.setPort(webui_port); 32 | 33 | const backend_port = webui.getFreePort(); 34 | std.debug.print("Free Port for custom web server: {d} \n", .{backend_port}); 35 | // now use the port: 36 | var buf1: [64]u8 = undefined; 37 | var buf2: [64]u8 = undefined; 38 | const port_argument1: []u8 = try std.fmt.bufPrintZ(&buf1, "{d}", .{backend_port}); 39 | const port_argument2: []u8 = try std.fmt.bufPrintZ(&buf2, "{d}", .{webui_port}); 40 | const argv = [_][]const u8{ "python", "./free_port_web_server.py", port_argument1, port_argument2 }; 41 | python_server_proc = std.process.Child.init(&argv, std.heap.page_allocator); 42 | 43 | // start the SPA web server: 44 | startPythonWebServer(); 45 | 46 | // Show a new window served by our custom web server (spawned above): 47 | var buf: [64]u8 = undefined; 48 | home_url = try std.fmt.bufPrintZ(&buf, "http://localhost:{d}/index.html", .{backend_port}); 49 | try nwin.show(home_url); 50 | 51 | // Wait until all windows get closed 52 | webui.wait(); 53 | 54 | // Free all memory resources (Optional) 55 | webui.clean(); 56 | 57 | // Free the spawned proc, port and memory 58 | killPythonWebServer(); 59 | } 60 | 61 | fn startPythonWebServer() void { 62 | if (python_running == false) { // a better check would be a test for the process itself 63 | if (python_server_proc.spawn()) |_| { 64 | python_running = true; 65 | std.debug.print("Spawned python server process PID={}\n", .{python_server_proc.id}); 66 | } else |err| { 67 | std.debug.print("NOT Starting python server: {}\n", .{err}); 68 | } 69 | } 70 | } 71 | 72 | fn killPythonWebServer() void { 73 | if (python_running == true) { 74 | if (python_server_proc.kill()) |_| { 75 | python_running = false; 76 | std.debug.print("Killing python server\n", .{}); 77 | } else |err| { 78 | std.debug.print("NOT Killing python server: {}\n", .{err}); 79 | } 80 | } 81 | } 82 | 83 | // This is a Zig function that is invoked by a Javascript call, 84 | // and in turn, calls Javascript. 85 | fn goto_page(e: *webui.Event) void { 86 | // JavaScript that invoked this function: gotoPage('some-path'); 87 | const path = e.getString(); 88 | std.debug.print("JS invoked Zig: Navigating to page: {s}\n", .{path}); 89 | // Now, write a Javascript call to do the navigation: 90 | var js: [64]u8 = std.mem.zeroes([64]u8); 91 | const buf = std.fmt.bufPrint(&js, "doNavigate('{s}');", .{path}) catch unreachable; 92 | // convert it to a Sentinel-Terminated slice 93 | const content: [:0]const u8 = js[0..buf.len :0]; 94 | std.debug.print("Zig calling JS: {s}\n", .{buf}); 95 | // Run the JavaScript 96 | e.getWindow().run(content); 97 | } 98 | 99 | fn events(e: *webui.Event) void { 100 | // This function gets called every time 101 | // there is an event 102 | switch (e.event_type) { 103 | .EVENT_CONNECTED => { 104 | std.debug.print("Connected. \n", .{}); 105 | }, 106 | .EVENT_DISCONNECTED => { 107 | std.debug.print("Disconnected. \n", .{}); 108 | }, 109 | .EVENT_MOUSE_CLICK => { 110 | std.debug.print("Click. \n", .{}); 111 | }, 112 | .EVENT_NAVIGATION => { 113 | // Because we used `bind(MyWindow, "", events);` 114 | // WebUI will block all `href` link clicks and sent here instead. 115 | // We can then control the behaviour of links as needed. 116 | // 117 | // In this SPA example, the client has its own router and 118 | // does the navigation for all pages in page.js (2nd, 3rd, 4th). 119 | // 120 | // However, for the 1st page, we have to handle navigation here: 121 | 122 | // get the url string 123 | const url = e.getString(); 124 | 125 | if (std.mem.eql(u8, url, home_url)) { 126 | // we use this to get widnow 127 | var win = e.getWindow(); 128 | 129 | std.debug.print("WebUI.js is Starting navigation to: {s}\n", .{url}); 130 | 131 | win.navigate(url); 132 | } else { 133 | std.debug.print("Client JS is navigating to: {s}\n", .{url}); 134 | // nothing to do, client is navigating 135 | } 136 | }, 137 | else => { 138 | std.debug.print("Other event {}. \n", .{e.event_type}); 139 | }, 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /examples/custom_spa_server_on_free_port/pages.js: -------------------------------------------------------------------------------- 1 | window.pages = [ 2 | { 3 | path: '/second-page', 4 | title: 'Second Page', 5 | html: '

This is the SECOND page


home' 6 | }, 7 | { 8 | path: '/third-page', 9 | title: 'Third Page', 10 | html: '

This is the THIRD page


home' 11 | }, 12 | { 13 | path: '/fourth-page', 14 | title: 'Fourth Page', 15 | html: '

This is the FOURTH page


home' 16 | }, 17 | ] 18 | const pages = window.pages; 19 | 20 | const router = function(path) { 21 | pages.forEach(route => { 22 | if(route.path === path) { 23 | window.history.pushState({}, route.title, path) 24 | document.getElementById('page').innerHTML = route.html 25 | } 26 | }) 27 | } 28 | window.router = router -------------------------------------------------------------------------------- /examples/custom_web_server/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | WebUI - Custom Web-Server Example (C) 6 | 7 | 8 | 9 | 10 |

Custom Web-Server Example (C)

11 |

12 | This HTML page is handled by a custom Web-Server other than WebUI.
13 | This window is connected to the back-end because we used:

http://localhost:8081/webui.js
14 |

15 |

Simple link example (Local file)

16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /examples/custom_web_server/main.zig: -------------------------------------------------------------------------------- 1 | //! Custom web Server Example 2 | const std = @import("std"); 3 | const webui = @import("webui"); 4 | 5 | pub fn main() !void { 6 | // Create new windows 7 | var nwin = webui.newWindow(); 8 | 9 | // Bind all events 10 | _ = try nwin.bind("", events); 11 | 12 | // Bind HTML elements with C functions 13 | _ = try nwin.bind("my_backend_func", my_backend_func); 14 | 15 | // Set the web-server/WebSocket port that WebUI should 16 | // use. This means `webui.js` will be available at: 17 | // http://localhost:MY_PORT_NUMBER/webui.js 18 | try nwin.setPort(8081); 19 | 20 | // Show a new window and show our custom web server 21 | // Assuming the custom web server is running on port 22 | // 8080... 23 | try nwin.show("http://localhost:8080/"); 24 | 25 | // Wait until all windows get closed 26 | webui.wait(); 27 | 28 | // Free all memory resources (Optional) 29 | webui.clean(); 30 | } 31 | 32 | fn events(e: *webui.Event) void { 33 | // This function gets called every time 34 | // there is an event 35 | 36 | switch (e.event_type) { 37 | .EVENT_CONNECTED => { 38 | std.debug.print("Connected. \n", .{}); 39 | }, 40 | .EVENT_DISCONNECTED => { 41 | std.debug.print("Disconnected. \n", .{}); 42 | }, 43 | .EVENT_MOUSE_CLICK => { 44 | std.debug.print("Click. \n", .{}); 45 | }, 46 | .EVENT_NAVIGATION => { 47 | 48 | // get the url string 49 | const url = e.getString(); 50 | 51 | // we use this to get widnow 52 | var win = e.getWindow(); 53 | 54 | std.debug.print("Starting navigation to: {s}\n", .{url}); 55 | 56 | // Because we used `bind(MyWindow, "", events);` 57 | // WebUI will block all `href` link clicks and sent here instead. 58 | // We can then control the behaviour of links as needed. 59 | 60 | win.navigate(url); 61 | }, 62 | else => {}, 63 | } 64 | } 65 | 66 | fn my_backend_func(e: *webui.Event) void { 67 | // JavaScript: 68 | // my_backend_func(123, 456, 789); 69 | // or webui.my_backend_func(...); 70 | 71 | const number_1 = e.getInt(); 72 | const number_2 = e.getIntAt(1); 73 | const number_3 = e.getIntAt(2); 74 | 75 | std.debug.print("my_backend_func 1: {}\n", .{number_1}); 76 | std.debug.print("my_backend_func 2: {}\n", .{number_2}); 77 | std.debug.print("my_backend_func 3: {}\n", .{number_3}); 78 | } 79 | -------------------------------------------------------------------------------- /examples/custom_web_server/second.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | WebUI - Custom Web-Server second page (C) 6 | 7 | 8 | 9 | 10 |

This is the second page !

11 |

Back

12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/custom_web_server/simple_web_server.py: -------------------------------------------------------------------------------- 1 | import http.server 2 | import socketserver 3 | 4 | PORT = 8080 5 | 6 | Handler = http.server.SimpleHTTPRequestHandler 7 | 8 | with socketserver.TCPServer(("", PORT), Handler) as httpd: 9 | print(f"Server started at http://localhost:{PORT}") 10 | httpd.serve_forever() 11 | -------------------------------------------------------------------------------- /examples/frameless/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 74 | 75 | 76 |
77 | WebUI Frameless Window 78 |
79 | 80 | 81 |
82 |
83 |
84 | This is a WebUI frameless example 85 |
86 | 87 | 88 | -------------------------------------------------------------------------------- /examples/frameless/main.zig: -------------------------------------------------------------------------------- 1 | //! WebUI Zig - FrameLess Example 2 | //! Note: This example needs to be manually linked to webview_loader when running on Windows 3 | //! Without webview_loader, it will report that the window is not found and exit immediately 4 | const webui = @import("webui"); 5 | 6 | // we use @embedFile to embed html 7 | const html = @embedFile("index.html"); 8 | 9 | fn minimize(e: *webui.Event) void { 10 | const win = e.getWindow(); 11 | win.minimize(); 12 | } 13 | 14 | fn maximize(e: *webui.Event) void { 15 | const win = e.getWindow(); 16 | win.maximize(); 17 | } 18 | 19 | fn close(e: *webui.Event) void { 20 | const win = e.getWindow(); 21 | win.close(); 22 | } 23 | 24 | pub fn main() !void { 25 | // create a new window 26 | var nwin = webui.newWindow(); 27 | 28 | _ = try nwin.bind("minimize", minimize); 29 | _ = try nwin.bind("maximize", maximize); 30 | _ = try nwin.bind("close", close); 31 | 32 | nwin.setSize(800, 600); 33 | nwin.setFrameless(true); 34 | nwin.setTransparent(true); 35 | nwin.setResizable(true); 36 | nwin.setCenter(); 37 | 38 | try nwin.showWv(html); 39 | 40 | // wait the window exit 41 | webui.wait(); 42 | } 43 | -------------------------------------------------------------------------------- /examples/minimal/main.zig: -------------------------------------------------------------------------------- 1 | //! WebUI Zig - Minimal Example 2 | const webui = @import("webui"); 3 | 4 | pub fn main() !void { 5 | // create a new window 6 | var nwin = webui.newWindow(); 7 | 8 | // show the content 9 | try nwin.show(" Hello World ! "); 10 | 11 | // wait the window exit 12 | webui.wait(); 13 | } 14 | -------------------------------------------------------------------------------- /examples/public_network_access/main.zig: -------------------------------------------------------------------------------- 1 | //! Public Network Access Example 2 | const std = @import("std"); 3 | const webui = @import("webui"); 4 | 5 | // embed the html 6 | const private_html = @embedFile("private.html"); 7 | const public_html = @embedFile("public.html"); 8 | 9 | // two windows 10 | var private_window: webui = undefined; 11 | var public_window: webui = undefined; 12 | 13 | fn app_exit(_: *webui.Event) void { 14 | webui.exit(); 15 | } 16 | 17 | fn public_window_events(e: *webui.Event) void { 18 | if (e.event_type == .EVENT_CONNECTED) { 19 | // New connection 20 | private_window.run("document.getElementById(\"Logs\").value += \"New connection.\\n\";"); 21 | } else if (e.event_type == .EVENT_DISCONNECTED) { 22 | // Disconnection 23 | private_window.run("document.getElementById(\"Logs\").value += \"Disconnected.\\n\";"); 24 | } 25 | } 26 | 27 | fn private_window_events(e: *webui.Event) void { 28 | if (e.event_type == .EVENT_CONNECTED) { 29 | const public_win_url: [:0]const u8 = public_window.getUrl() catch return; 30 | var buf = std.mem.zeroes([1024]u8); 31 | const js = std.fmt.bufPrintZ(&buf, "document.getElementById('urlSpan').innerHTML = '{s}';", .{public_win_url}) catch unreachable; 32 | private_window.run(js); 33 | } 34 | } 35 | 36 | pub fn main() !void { 37 | // Create windows 38 | private_window = webui.newWindow(); 39 | public_window = webui.newWindow(); 40 | 41 | // App 42 | webui.setTimeout(0); // Wait forever (never timeout) 43 | 44 | // Public Window 45 | // Make URL accessible from public networks 46 | public_window.setPublic(true); 47 | 48 | // Bind all events 49 | _ = try public_window.bind("", public_window_events); 50 | 51 | // Set public window HTML 52 | try public_window.showBrowser(public_html, .NoBrowser); 53 | 54 | // Main Private Window 55 | 56 | // Run Js 57 | _ = try private_window.bind("", private_window_events); 58 | 59 | // Bind exit button 60 | _ = try private_window.bind("Exit", app_exit); 61 | 62 | // Show the window 63 | _ = try private_window.show(private_html); 64 | 65 | // Wait until all windows get closed 66 | webui.wait(); 67 | 68 | // Free all memory resources (Optional) 69 | webui.clean(); 70 | } 71 | -------------------------------------------------------------------------------- /examples/public_network_access/private.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Public Network Access Example 7 | 41 | 42 | 43 |

WebUI - Public Network Access Example

44 |
45 | The second public window is configured to be accessible from
46 | any device in the public network.
47 |
48 | Second public window link:
49 |

...

50 | Second public window events:
51 | 52 |
53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /examples/public_network_access/public.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Welcome to Public UI 7 | 8 | 9 |

Welcome to Public UI!

10 | 11 | 12 | -------------------------------------------------------------------------------- /examples/serve_a_folder/bun_test.ts: -------------------------------------------------------------------------------- 1 | // This file gets called like follow: 2 | // 3 | // 1. UI `Index.html` request: 4 | // `http://localhost:xxx/bun_test.ts?foo=123&bar=456` 5 | // 6 | // 2. WebUI runs command: 7 | // `bun run "bun_test.ts" "foo=123&bar=456"` 8 | // 9 | // 3. Bun parses args and prints the response 10 | 11 | // Get Query (HTTP GET) 12 | const args = process.argv.slice(2); 13 | const query = args[0]; 14 | 15 | // Variables 16 | let foo: string = ''; 17 | let bar: string = ''; 18 | 19 | // Read Query 20 | const params = new URLSearchParams(query); 21 | for (const [key, value] of params.entries()) { 22 | if (key === 'foo') foo = value; // 123 23 | else if (key === 'bar') bar = value; // 456 24 | } 25 | 26 | console.log('Response from Bun: ' + (parseInt(foo) + parseInt(bar))); // 579 27 | -------------------------------------------------------------------------------- /examples/serve_a_folder/deno_test.ts: -------------------------------------------------------------------------------- 1 | // This file gets called like follow: 2 | // 3 | // 1. UI `Index.html` request: 4 | // `http://localhost:xxx/deno_test.ts?foo=123&bar=456` 5 | // 6 | // 2. WebUI runs command: 7 | // `deno run --allow-all --unstable "deno_test.ts" "foo=123&bar=456"` 8 | // 9 | // 3. Deno parse args and print the response 10 | 11 | // Import parse() 12 | import { parse } from 'https://deno.land/std/flags/mod.ts'; 13 | 14 | // Get Query (HTTP GET) 15 | const args = parse(Deno.args); 16 | const query = args._[0] as string; 17 | 18 | // Variables 19 | let foo: string = ''; 20 | let bar: string = ''; 21 | 22 | // Read Query 23 | const params = new URLSearchParams(query); 24 | for (const [key, value] of params.entries()) { 25 | if (key == 'foo') foo = value; // 123 26 | else if (key == 'bar') bar = value; // 456 27 | } 28 | 29 | console.log('Response from Deno: ' + (parseInt(foo) + parseInt(bar))); // 579 30 | -------------------------------------------------------------------------------- /examples/serve_a_folder/dynamic.txt: -------------------------------------------------------------------------------- 1 | 2 | This is a dynamic file content example.
3 | Count: {} [Refresh]
4 | 5 | 6 | -------------------------------------------------------------------------------- /examples/serve_a_folder/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | WebUI - Serve a Folder Example (C) 6 | 52 | 53 | 54 |

Serve a Folder Example (C)

55 |
56 |

57 | You can edit this HTML file as you need.
58 | Also, you can config WebUI to use Deno or Nodejs runtime for your JS/TS files.
59 |
60 | Please click on the link to switch to the second page
61 | Or click on the button to switch to the second page programmatically. 62 |

63 |
64 | Click on [deno_test.ts] to interpret the TypeScript file (If deno is installed) 65 |
66 | By a simple HTTP request "deno_test.ts?foo=60&bar=40" 67 |
68 |
69 | 70 |
71 |
72 | 73 |
74 |
75 | 76 |
77 |

Second Page As A Simple Link (Local file)

78 |
79 | 80 |
81 |
82 | 83 |
84 |

Static file example (Embedded)

85 |

Dynamic file example (Embedded)

86 |

87 | Unicode Test:

88 | مرحبًا
89 | 你好
90 | こんにちは 91 |

92 | 93 | 94 | 95 | 96 | 97 | 193 | 194 | -------------------------------------------------------------------------------- /examples/serve_a_folder/main.zig: -------------------------------------------------------------------------------- 1 | //!Serve a Folder Example 2 | const std = @import("std"); 3 | const webui = @import("webui"); 4 | const test_txt = @embedFile("test.txt"); 5 | const dynamic_txt = @embedFile("dynamic.txt"); 6 | 7 | var MyWindow: webui = undefined; 8 | var MySecondWindow: webui = undefined; 9 | 10 | pub fn main() !void { 11 | // Create new windows 12 | MyWindow = try webui.newWindowWithId(1); 13 | MySecondWindow = try webui.newWindowWithId(2); 14 | 15 | // Bind HTML element IDs with a C functions 16 | _ = try MyWindow.bind("SwitchToSecondPage", switch_second_window); 17 | _ = try MyWindow.bind("OpenNewWindow", show_second_window); 18 | _ = try MyWindow.bind("Exit", exit_app); 19 | _ = try MySecondWindow.bind("Exit", exit_app); 20 | 21 | // Bind events 22 | _ = try MyWindow.bind("", events); 23 | 24 | // Set the `.ts` and `.js` runtime 25 | // webui_set_runtime(MyWindow, NodeJS); 26 | // webui_set_runtime(MyWindow, Bun); 27 | MyWindow.setRuntime(.Deno); 28 | 29 | // Set a custom files handler 30 | MyWindow.setFileHandler(my_files_handler); 31 | 32 | // Set window size 33 | MyWindow.setSize(800, 800); 34 | 35 | // Set window position 36 | MyWindow.setPosition(200, 200); 37 | 38 | // Show a new window 39 | // webui_set_root_folder(MyWindow, "_MY_PATH_HERE_"); 40 | // webui_show_browser(MyWindow, "index.html", Chrome); 41 | try MyWindow.show("index.html"); 42 | 43 | // Wait until all windows get closed 44 | webui.wait(); 45 | 46 | // Free all memory resources (Optional) 47 | webui.clean(); 48 | } 49 | 50 | fn exit_app(_: *webui.Event) void { 51 | // Close all opened windows 52 | webui.exit(); 53 | } 54 | 55 | fn events(e: *webui.Event) void { 56 | // This function gets called every time 57 | // there is an event 58 | switch (e.event_type) { 59 | .EVENT_CONNECTED => { 60 | std.debug.print("Connected. \n", .{}); 61 | }, 62 | .EVENT_DISCONNECTED => { 63 | std.debug.print("Disconnected. \n", .{}); 64 | }, 65 | .EVENT_MOUSE_CLICK => { 66 | std.debug.print("Click. \n", .{}); 67 | }, 68 | .EVENT_NAVIGATION => { 69 | const url = e.getString(); 70 | const win = e.getWindow(); 71 | 72 | std.debug.print("start to navigate to {s}\n", .{url}); 73 | 74 | // Because we used `MyWindow.bind("", events);` 75 | // WebUI will block all `href` link clicks and sent here instead. 76 | // We can then control the behaviour of links as needed. 77 | win.navigate(url); 78 | }, 79 | else => {}, 80 | } 81 | } 82 | 83 | fn switch_second_window(e: *webui.Event) void { 84 | // This function gets called every 85 | // time the user clicks on "SwitchToSecondPage" 86 | 87 | // Switch to `/second.html` in the same opened window. 88 | e.getWindow().show("second.html") catch return; 89 | } 90 | 91 | fn show_second_window(_: *webui.Event) void { 92 | // This function gets called every 93 | // time the user clicks on "OpenNewWindow" 94 | 95 | // Show a new window, and navigate to `/second.html` 96 | // if it's already open, then switch in the same window 97 | MySecondWindow.show("second.html") catch return; 98 | } 99 | 100 | var count: i32 = 0; 101 | 102 | fn my_files_handler(filename: []const u8) ?[]const u8 { 103 | std.debug.print("File: {s}\n", .{filename}); 104 | 105 | if (std.mem.eql(u8, filename, "/test.txt")) { 106 | // Const static file example 107 | return test_txt; 108 | } else if (std.mem.eql(u8, filename, "/dynamic.html")) { 109 | const body = webui.malloc(1024) catch unreachable; 110 | defer webui.free(body); 111 | const header_and_body = webui.malloc(1024) catch unreachable; 112 | 113 | count += 1; 114 | 115 | const buf = std.fmt.bufPrint(body, dynamic_txt, .{count}) catch unreachable; 116 | 117 | const content = std.fmt.bufPrint(header_and_body, 118 | \\HTTP/1.1 200 OK 119 | \\Content-Type: text/html 120 | \\Content-Length: {} 121 | \\ 122 | \\{s} 123 | , .{ buf.len, buf }) catch unreachable; 124 | 125 | // Generate header + body 126 | 127 | // By allocating resources using webui.malloc() 128 | // WebUI will automaticaly free the resources. 129 | return content; 130 | } 131 | 132 | return null; 133 | } 134 | -------------------------------------------------------------------------------- /examples/serve_a_folder/node_test.js: -------------------------------------------------------------------------------- 1 | // This file gets called like follow: 2 | // 3 | // 1. UI `Index.html` request: 4 | // `http://localhost:xxx/node_test.js?foo=123&bar=456` 5 | // 6 | // 2. WebUI runs command: 7 | // `node node_test.js "foo=123&bar=456"` 8 | // 9 | // 3. Node.js parses args and prints the response 10 | 11 | // Get Query (HTTP GET) 12 | const args = process.argv.slice(2); 13 | const query = args[0]; 14 | 15 | // Variables 16 | let foo = ''; 17 | let bar = ''; 18 | 19 | // Read Query 20 | const params = new URLSearchParams(query); 21 | for (const [key, value] of params.entries()) { 22 | if (key === 'foo') foo = value; // 123 23 | else if (key === 'bar') bar = value; // 456 24 | } 25 | 26 | console.log('Response from Node.js: ' + (parseInt(foo) + parseInt(bar))); // 579 27 | -------------------------------------------------------------------------------- /examples/serve_a_folder/second.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | WebUI - Second Page (C) 6 | 39 | 40 | 41 |

This is the second page !

42 |
43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /examples/serve_a_folder/test.txt: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Content-Type: text/html 3 | Content-Length: 99 4 | 5 | 6 | This is a static embedded file content example. 7 | 8 | 9 | -------------------------------------------------------------------------------- /examples/text_editor/main.zig: -------------------------------------------------------------------------------- 1 | //! Text Editor in Zig using WebUI 2 | const std = @import("std"); 3 | const webui = @import("webui"); 4 | 5 | fn close(_: *webui.Event) void { 6 | std.debug.print("Exit.\n", .{}); 7 | 8 | // Close all opened windows 9 | webui.exit(); 10 | } 11 | 12 | pub fn main() !void { 13 | // Create a new window 14 | var mainW = webui.newWindow(); 15 | 16 | // Set the root folder for the UI 17 | try mainW.setRootFolder("ui"); 18 | 19 | // Bind HTML elements with the specified ID to C functions 20 | _ = try mainW.bind("close_app", close); 21 | 22 | // Show the window, this will select the best browser to show 23 | // and you can use showBrowser to select which browser will be used 24 | try mainW.show("index.html"); 25 | 26 | // Wait until all windows get closed 27 | webui.wait(); 28 | 29 | // Free all memory resources (Optional) 30 | webui.clean(); 31 | } 32 | -------------------------------------------------------------------------------- /examples/text_editor/ui/css/codemirror.min.css: -------------------------------------------------------------------------------- 1 | .CodeMirror{font-family:monospace;height:300px;color:#000;direction:ltr}.CodeMirror-lines{padding:4px 0}.CodeMirror pre.CodeMirror-line,.CodeMirror pre.CodeMirror-line-like{padding:0 4px}.CodeMirror-gutter-filler,.CodeMirror-scrollbar-filler{background-color:#fff}.CodeMirror-gutters{border-right:1px solid #ddd;background-color:#f7f7f7;white-space:nowrap}.CodeMirror-linenumber{padding:0 3px 0 5px;min-width:20px;text-align:right;color:#999;white-space:nowrap}.CodeMirror-guttermarker{color:#000}.CodeMirror-guttermarker-subtle{color:#999}.CodeMirror-cursor{border-left:1px solid #000;border-right:none;width:0}.CodeMirror div.CodeMirror-secondarycursor{border-left:1px solid silver}.cm-fat-cursor .CodeMirror-cursor{width:auto;border:0!important;background:#7e7}.cm-fat-cursor div.CodeMirror-cursors{z-index:1}.cm-fat-cursor .CodeMirror-line::selection,.cm-fat-cursor .CodeMirror-line>span::selection,.cm-fat-cursor .CodeMirror-line>span>span::selection{background:0 0}.cm-fat-cursor .CodeMirror-line::-moz-selection,.cm-fat-cursor .CodeMirror-line>span::-moz-selection,.cm-fat-cursor .CodeMirror-line>span>span::-moz-selection{background:0 0}.cm-fat-cursor{caret-color:transparent}@-moz-keyframes blink{50%{background-color:transparent}}@-webkit-keyframes blink{50%{background-color:transparent}}@keyframes blink{50%{background-color:transparent}}.cm-tab{display:inline-block;text-decoration:inherit}.CodeMirror-rulers{position:absolute;left:0;right:0;top:-50px;bottom:0;overflow:hidden}.CodeMirror-ruler{border-left:1px solid #ccc;top:0;bottom:0;position:absolute}.cm-s-default .cm-header{color:#00f}.cm-s-default .cm-quote{color:#090}.cm-negative{color:#d44}.cm-positive{color:#292}.cm-header,.cm-strong{font-weight:700}.cm-em{font-style:italic}.cm-link{text-decoration:underline}.cm-strikethrough{text-decoration:line-through}.cm-s-default .cm-keyword{color:#708}.cm-s-default .cm-atom{color:#219}.cm-s-default .cm-number{color:#164}.cm-s-default .cm-def{color:#00f}.cm-s-default .cm-variable-2{color:#05a}.cm-s-default .cm-type,.cm-s-default .cm-variable-3{color:#085}.cm-s-default .cm-comment{color:#a50}.cm-s-default .cm-string{color:#a11}.cm-s-default .cm-string-2{color:#f50}.cm-s-default .cm-meta{color:#555}.cm-s-default .cm-qualifier{color:#555}.cm-s-default .cm-builtin{color:#30a}.cm-s-default .cm-bracket{color:#997}.cm-s-default .cm-tag{color:#170}.cm-s-default .cm-attribute{color:#00c}.cm-s-default .cm-hr{color:#999}.cm-s-default .cm-link{color:#00c}.cm-s-default .cm-error{color:red}.cm-invalidchar{color:red}.CodeMirror-composing{border-bottom:2px solid}div.CodeMirror span.CodeMirror-matchingbracket{color:#0b0}div.CodeMirror span.CodeMirror-nonmatchingbracket{color:#a22}.CodeMirror-matchingtag{background:rgba(255,150,0,.3)}.CodeMirror-activeline-background{background:#e8f2ff}.CodeMirror{position:relative;overflow:hidden;background:#fff}.CodeMirror-scroll{overflow:scroll!important;margin-bottom:-50px;margin-right:-50px;padding-bottom:50px;height:100%;outline:0;position:relative;z-index:0}.CodeMirror-sizer{position:relative;border-right:50px solid transparent}.CodeMirror-gutter-filler,.CodeMirror-hscrollbar,.CodeMirror-scrollbar-filler,.CodeMirror-vscrollbar{position:absolute;z-index:6;display:none;outline:0}.CodeMirror-vscrollbar{right:0;top:0;overflow-x:hidden;overflow-y:scroll}.CodeMirror-hscrollbar{bottom:0;left:0;overflow-y:hidden;overflow-x:scroll}.CodeMirror-scrollbar-filler{right:0;bottom:0}.CodeMirror-gutter-filler{left:0;bottom:0}.CodeMirror-gutters{position:absolute;left:0;top:0;min-height:100%;z-index:3}.CodeMirror-gutter{white-space:normal;height:100%;display:inline-block;vertical-align:top;margin-bottom:-50px}.CodeMirror-gutter-wrapper{position:absolute;z-index:4;background:0 0!important;border:none!important}.CodeMirror-gutter-background{position:absolute;top:0;bottom:0;z-index:4}.CodeMirror-gutter-elt{position:absolute;cursor:default;z-index:4}.CodeMirror-gutter-wrapper ::selection{background-color:transparent}.CodeMirror-gutter-wrapper ::-moz-selection{background-color:transparent}.CodeMirror-lines{cursor:text;min-height:1px}.CodeMirror pre.CodeMirror-line,.CodeMirror pre.CodeMirror-line-like{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0;border-width:0;background:0 0;font-family:inherit;font-size:inherit;margin:0;white-space:pre;word-wrap:normal;line-height:inherit;color:inherit;z-index:2;position:relative;overflow:visible;-webkit-tap-highlight-color:transparent;-webkit-font-variant-ligatures:contextual;font-variant-ligatures:contextual}.CodeMirror-wrap pre.CodeMirror-line,.CodeMirror-wrap pre.CodeMirror-line-like{word-wrap:break-word;white-space:pre-wrap;word-break:normal}.CodeMirror-linebackground{position:absolute;left:0;right:0;top:0;bottom:0;z-index:0}.CodeMirror-linewidget{position:relative;z-index:2;padding:.1px}.CodeMirror-rtl pre{direction:rtl}.CodeMirror-code{outline:0}.CodeMirror-gutter,.CodeMirror-gutters,.CodeMirror-linenumber,.CodeMirror-scroll,.CodeMirror-sizer{-moz-box-sizing:content-box;box-sizing:content-box}.CodeMirror-measure{position:absolute;width:100%;height:0;overflow:hidden;visibility:hidden}.CodeMirror-cursor{position:absolute;pointer-events:none}.CodeMirror-measure pre{position:static}div.CodeMirror-cursors{visibility:hidden;position:relative;z-index:3}div.CodeMirror-dragcursors{visibility:visible}.CodeMirror-focused div.CodeMirror-cursors{visibility:visible}.CodeMirror-selected{background:#d9d9d9}.CodeMirror-focused .CodeMirror-selected{background:#d7d4f0}.CodeMirror-crosshair{cursor:crosshair}.CodeMirror-line::selection,.CodeMirror-line>span::selection,.CodeMirror-line>span>span::selection{background:#d7d4f0}.CodeMirror-line::-moz-selection,.CodeMirror-line>span::-moz-selection,.CodeMirror-line>span>span::-moz-selection{background:#d7d4f0}.cm-searching{background-color:#ffa;background-color:rgba(255,255,0,.4)}.cm-force-border{padding-right:.1px}@media print{.CodeMirror div.CodeMirror-cursors{visibility:hidden}}.cm-tab-wrap-hack:after{content:''}span.CodeMirror-selectedtext{background:0 0} -------------------------------------------------------------------------------- /examples/text_editor/ui/css/lucario.css: -------------------------------------------------------------------------------- 1 | /* 2 | Name: lucario 3 | Author: Raphael Amorim 4 | Original Lucario color scheme (https://github.com/raphamorim/lucario) 5 | Modified for WebUI Text Editor. 6 | */ 7 | 8 | .cm-s-lucario.CodeMirror, .cm-s-lucario .CodeMirror-gutters { 9 | /* background-color: #2b3e50 !important; */ 10 | color: #f8f8f2 !important; 11 | border: none; 12 | background: #f8f9fa !important; 13 | background-color: rgba(0, 0, 0, .0) !important; 14 | } 15 | .cm-s-lucario .CodeMirror-gutters { color: #2b3e50; } 16 | .cm-s-lucario .CodeMirror-cursor { border-left: solid thin #E6C845; } 17 | .cm-s-lucario .CodeMirror-linenumber { color: #f8f8f2; background-color: rgba(0, 0, 0, .2) !important; } 18 | .cm-s-lucario .CodeMirror-selected { background: #243443; } 19 | .cm-s-lucario .CodeMirror-line::selection, .cm-s-lucario .CodeMirror-line > span::selection, .cm-s-lucario .CodeMirror-line > span > span::selection { background: #243443; } 20 | .cm-s-lucario .CodeMirror-line::-moz-selection, .cm-s-lucario .CodeMirror-line > span::-moz-selection, .cm-s-lucario .CodeMirror-line > span > span::-moz-selection { background: #243443; } 21 | .cm-s-lucario span.cm-comment { color: #5c98cd; } 22 | .cm-s-lucario span.cm-string, .cm-s-lucario span.cm-string-2 { color: #E6DB74; } 23 | .cm-s-lucario span.cm-number { color: #ca94ff; } 24 | .cm-s-lucario span.cm-variable { color: #f8f8f2; } 25 | .cm-s-lucario span.cm-variable-2 { color: #f8f8f2; } 26 | .cm-s-lucario span.cm-def { color: #72C05D; } 27 | .cm-s-lucario span.cm-operator { color: #66D9EF; } 28 | .cm-s-lucario span.cm-keyword { color: #ff6541; } 29 | .cm-s-lucario span.cm-atom { color: #bd93f9; } 30 | .cm-s-lucario span.cm-meta { color: #f8f8f2; } 31 | .cm-s-lucario span.cm-tag { color: #ff6541; } 32 | .cm-s-lucario span.cm-attribute { color: #66D9EF; } 33 | .cm-s-lucario span.cm-qualifier { color: #72C05D; } 34 | .cm-s-lucario span.cm-property { color: #f8f8f2; } 35 | .cm-s-lucario span.cm-builtin { color: #72C05D; } 36 | .cm-s-lucario span.cm-variable-3, .cm-s-lucario span.cm-type { color: #ffb86c; } 37 | .cm-s-lucario .CodeMirror-activeline-background { background: #243443; } 38 | .cm-s-lucario .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; } 39 | .cm-s-lucario .CodeMirror-scroll { overflow: hidden; } 40 | -------------------------------------------------------------------------------- /examples/text_editor/ui/css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | height: 100vh; 5 | font-family: 'Courier New', Courier, monospace; 6 | background-image: linear-gradient(to right top, #8e44ad 0%, #3498db 100%); 7 | background-repeat: no-repeat; 8 | background-position: center center; 9 | background-size: cover; 10 | background-attachment: fixed; 11 | color: #ddecf9; 12 | } 13 | 14 | .topbar { 15 | width: 100%; 16 | height: 4px; 17 | background-image: linear-gradient(to right, #4ed2e7 0%, #db57eb 50%, #f98818 100%); 18 | } 19 | 20 | header { 21 | color: #fff; 22 | } 23 | 24 | /* Nav */ 25 | 26 | nav { 27 | background: linear-gradient( 28 | 90deg, 29 | rgba(255, 255, 255, 0) 0%, 30 | rgba(255, 255, 255, 0.2) 25%, 31 | rgba(255, 255, 255, 0.2) 75%, 32 | rgba(255, 255, 255, 0) 100% 33 | ); 34 | box-shadow: 35 | 0 0 25px rgba(0, 0, 0, 0.1), 36 | inset 0 0 1px rgba(255, 255, 255, 0.6); 37 | text-align: center; 38 | } 39 | 40 | nav button { 41 | background: none; 42 | border: none; 43 | text-shadow: 1px 1px 2px #000000; 44 | font-family: 'Font Awesome 5 Free'; 45 | font-size: 18px; 46 | color: #ddecf9; 47 | cursor: pointer; 48 | margin: 0 auto; 49 | padding: 18px; 50 | } 51 | 52 | nav button:hover { 53 | box-shadow: 54 | 0 0 10px rgba(0, 0, 0, 0.1), 55 | inset 0 0 1px rgba(255, 255, 255, 0.6); 56 | background: rgba(255, 255, 255, 0.1); 57 | } 58 | 59 | nav #save-btn:disabled { 60 | pointer-events: none; 61 | color: #7ca0df; 62 | } 63 | 64 | nav button i { 65 | /* Click through the icon in the button */ 66 | pointer-events: none; 67 | } 68 | 69 | /* Code */ 70 | 71 | .main { 72 | padding: 0px; 73 | } 74 | 75 | /* About */ 76 | 77 | .about-box { 78 | display: none; 79 | position: fixed; 80 | z-index: 1; 81 | left: 0; 82 | top: 0; 83 | width: 100%; 84 | height: 100%; 85 | background-image: linear-gradient(to right top, #8e44ad 0%, #3498db 100%); 86 | } 87 | 88 | .about-box-content { 89 | background-image: linear-gradient(to right top, #8e44ad 0%, #3498db 100%); 90 | position: absolute; 91 | margin: 0; 92 | padding: 10px; 93 | width: 30%; 94 | border-radius: 5px; 95 | top: 50%; 96 | left: 50%; 97 | transform: translate(-50%, -50%); 98 | } 99 | 100 | .about-box-content h1 { 101 | text-align: center; 102 | } 103 | 104 | .about-box-content a { 105 | color: inherit; 106 | } 107 | 108 | .CodeMirror { 109 | height: 100%; 110 | font-family: 'Courier New', Courier, monospace; 111 | font-size: 16px; 112 | text-shadow: 1px 1px 2px #000000; 113 | } 114 | -------------------------------------------------------------------------------- /examples/text_editor/ui/img/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webui-dev/zig-webui/a58faf0fb206725ee443d1af6f6b1ebc88187e6a/examples/text_editor/ui/img/icon.png -------------------------------------------------------------------------------- /examples/text_editor/ui/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Text Editor in Zig using WebUI 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 30 |
31 | 32 |
33 |
34 |
35 |

WebUI Text Editor

36 | v1.1 37 |

Example of a text editor software in Zig using WebUI library.

38 |

39 | webui.me | (C)2025 40 | Hassan Draga 41 |

42 |
43 |
44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /examples/text_editor/ui/js/clike.min.js: -------------------------------------------------------------------------------- 1 | !function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(M){"use strict";function L(e,t,n,r,o,a){this.indented=e,this.column=t,this.type=n,this.info=r,this.align=o,this.prev=a}function D(e,t,n,r){var o=e.indented;e.context&&"statement"==e.context.type&&"statement"!=n&&(o=e.context.indented),e.context=new L(o,t,n,r,null,e.context)}function P(e){var t=e.context.type;return")"!=t&&"]"!=t&&"}"!=t||(e.indented=e.context.indented),e.context=e.context.prev}function E(e,t,n){return"variable"==t.prevToken||"type"==t.prevToken||(!!/\S(?:[^- ]>|[*\]])\s*$|\*$/.test(e.string.slice(0,n))||(!(!t.typeAtEndOfLine||e.column()!=e.indentation())||void 0))}function z(e){for(;;){if(!e||"top"==e.type)return 1;if("}"==e.type&&"namespace"!=e.prev.info)return;e=e.prev}}function e(e){for(var t={},n=e.split(" "),r=0;r!?|\/]/,S=a.isIdentifierChar||/[\w\$_\xa1-\uffff]/,T=a.isReservedIdentifier||!1;function C(e,t){var a,n=e.next();if(y[n]){var r=y[n](e,t);if(!1!==r)return r}if('"'==n||"'"==n)return t.tokenize=(a=n,function(e,t){for(var n,r=!1,o=!1;null!=(n=e.next());){if(n==a&&!r){o=!0;break}r=!r&&"\\"==n}return!o&&(r||g)||(t.tokenize=null),"string"}),t.tokenize(e,t);if(v.test(n)){if(e.backUp(1),e.match(w))return"number";e.next()}if(x.test(n))return i=n,null;if("/"==n){if(e.eat("*"))return(t.tokenize=I)(e,t);if(e.eat("/"))return e.skipToEnd(),"comment"}if(_.test(n)){for(;!e.match(/^\/[\/*]/,!1)&&e.eat(_););return"operator"}if(e.eatWhile(S),b)for(;e.match(b);)e.eatWhile(S);r=e.current();return F(o,r)?(F(p,r)&&(i="newstatement"),F(m,r)&&(l=!0),"keyword"):F(d,r)?"type":F(f,r)||T&&T(r)?(F(p,r)&&(i="newstatement"),"builtin"):F(h,r)?"atom":"variable"}function I(e,t){for(var n,r=!1;n=e.next();){if("/"==n&&r){t.tokenize=null;break}r="*"==n}return"comment"}function N(e,t){a.typeFirstDefinitions&&e.eol()&&z(t.context)&&(t.typeAtEndOfLine=E(e,t,e.pos))}return{startState:function(e){return{tokenize:null,context:new L((e||0)-s,0,"top",null,!1),indented:0,startOfLine:!0,prevToken:null}},token:function(e,t){var n=t.context;if(e.sol()&&(null==n.align&&(n.align=!1),t.indented=e.indentation(),t.startOfLine=!0),e.eatSpace())return N(e,t),null;i=l=null;var r,o=(t.tokenize||C)(e,t);if("comment"==o||"meta"==o)return o;if(null==n.align&&(n.align=!0),";"==i||":"==i||","==i&&e.match(/^\s*(?:\/\/.*)?$/,!1))for(;"statement"==t.context.type;)P(t);else if("{"==i)D(t,e.column(),"}");else if("["==i)D(t,e.column(),"]");else if("("==i)D(t,e.column(),")");else if("}"==i){for(;"statement"==n.type;)n=P(t);for("}"==n.type&&(n=P(t));"statement"==n.type;)n=P(t)}else i==n.type?P(t):k&&(("}"==n.type||"top"==n.type)&&";"!=i||"statement"==n.type&&"newstatement"==i)&&D(t,e.column(),"statement",e.current());return"variable"==o&&("def"==t.prevToken||a.typeFirstDefinitions&&E(e,t,e.start)&&z(t.context)&&e.match(/^\s*\(/,!1))&&(o="def"),"def"==(o=y.token&&void 0!==(r=y.token(e,t,o))?r:o)&&!1===a.styleDefs&&(o="variable"),t.startOfLine=!1,t.prevToken=l?"def":o||i,N(e,t),o},indent:function(e,t){if(e.tokenize!=C&&null!=e.tokenize||e.typeAtEndOfLine)return M.Pass;var n=e.context,r=t&&t.charAt(0),o=r==n.type;if("statement"==n.type&&"}"==r&&(n=n.prev),a.dontIndentStatements)for(;"statement"==n.type&&a.dontIndentStatements.test(n.info);)n=n.prev;if(y.indent){e=y.indent(e,n,t,s);if("number"==typeof e)return e}e=n.prev&&"switch"==n.prev.info;if(a.allmanIndentation&&/[{(]/.test(r)){for(;"top"!=n.type&&"}"!=n.type;)n=n.prev;return n.indented}return"statement"==n.type?n.indented+("{"==r?0:c):!n.align||u&&")"==n.type?")"!=n.type||o?n.indented+(o?0:s)+(o||!e||/^(?:case|default)\b/.test(t)?0:s):n.indented+c:n.column+(o?0:1)},electricInput:e?/^\s*(?:case .*?:|default:|\{\}?|\})$/:/^\s*[{}]$/,blockCommentStart:"/*",blockCommentEnd:"*/",blockCommentContinue:" * ",lineComment:"//",fold:"brace"}});var t="auto if break case register continue return default do sizeof static else struct switch extern typedef union for goto while enum const volatile inline restrict asm fortran",n="alignas alignof and and_eq audit axiom bitand bitor catch class compl concept constexpr const_cast decltype delete dynamic_cast explicit export final friend import module mutable namespace new noexcept not not_eq operator or or_eq override private protected public reinterpret_cast requires static_assert static_cast template this thread_local throw try typeid typename using virtual xor xor_eq",r="bycopy byref in inout oneway out self super atomic nonatomic retain copy readwrite readonly strong weak assign typeof nullable nonnull null_resettable _cmd @interface @implementation @end @protocol @encode @property @synthesize @dynamic @class @public @package @private @protected @required @optional @try @catch @finally @import @selector @encode @defs @synchronized @autoreleasepool @compatibility_alias @available",o="FOUNDATION_EXPORT FOUNDATION_EXTERN NS_INLINE NS_FORMAT_FUNCTION NS_RETURNS_RETAINEDNS_ERROR_ENUM NS_RETURNS_NOT_RETAINED NS_RETURNS_INNER_POINTER NS_DESIGNATED_INITIALIZER NS_ENUM NS_OPTIONS NS_REQUIRES_NIL_TERMINATION NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_END NS_SWIFT_NAME NS_REFINED_FOR_SWIFT",a=e("int long char short double float unsigned signed void bool"),i=e("SEL instancetype id Class Protocol BOOL");function l(e){return F(a,e)||/.+_t$/.test(e)}function s(e){return l(e)||F(i,e)}var c="case do else for if switch while struct enum union",u="struct enum union";function d(e,t){if(!t.startOfLine)return!1;for(var n,r=null;n=e.peek();){if("\\"==n&&e.match(/^.$/)){r=d;break}if("/"==n&&e.match(/^\/[\/\*]/,!1))break;e.next()}return t.tokenize=r,"meta"}function f(e,t){return"type"==t.prevToken&&"type"}function p(e){return!(!e||e.length<2)&&("_"==e[0]&&("_"==e[1]||e[1]!==e[1].toLowerCase()))}function m(e){return e.eatWhile(/[\w\.']/),"number"}function h(e,t){var n;return e.backUp(1),e.match(/^(?:R|u8R|uR|UR|LR)/)?!!(n=e.match(/^"([^\s\\()]{0,16})\(/))&&(t.cpp11RawStringDelim=n[1],(t.tokenize=k)(e,t)):e.match(/^(?:u8|u|U|L)/)?!!e.match(/^["']/,!1)&&"string":(e.next(),!1)}function y(e){e=/(\w+)::~?(\w+)$/.exec(e);return e&&e[1]==e[2]}function g(e,t){for(var n;null!=(n=e.next());)if('"'==n&&!e.eat('"')){t.tokenize=null;break}return"string"}function k(e,t){var n=t.cpp11RawStringDelim.replace(/[^\w\s]/g,"\\$&");return e.match(new RegExp(".*?\\)"+n+'"'))?t.tokenize=null:e.skipToEnd(),"string"}function b(e,t){"string"==typeof e&&(e=[e]);var n=[];function r(e){if(e)for(var t in e)e.hasOwnProperty(t)&&n.push(t)}r(t.keywords),r(t.types),r(t.builtin),r(t.atoms),n.length&&(t.helperType=e[0],M.registerHelper("hintWords",e[0],n));for(var o=0;o!?|\/#:@]/,hooks:{"@":function(e){return e.eatWhile(/[\w\$_]/),"meta"},'"':function(e,t){return!!e.match('""')&&(t.tokenize=x,t.tokenize(e,t))},"'":function(e){return e.eatWhile(/[\w\$_\xa1-\uffff]/),"atom"},"=":function(e,t){var n=t.context;return!("}"!=n.type||!n.align||!e.eat(">"))&&(t.context=new L(n.indented,n.column,n.type,n.info,null,n.prev),"operator")},"/":function(e,t){return!!e.eat("*")&&(t.tokenize=v(1),t.tokenize(e,t))}},modeProps:{closeBrackets:{pairs:'()[]{}""',triples:'"'}}}),b("text/x-kotlin",{name:"clike",keywords:e("package as typealias class interface this super val operator var fun for is in This throw return annotation break continue object if else while do try when !in !is as? file import where by get set abstract enum open inner override private public internal protected catch finally out final vararg reified dynamic companion constructor init sealed field property receiver param sparam lateinit data inline noinline tailrec external annotation crossinline const operator infix suspend actual expect setparam value"),types:e("Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable Compiler Double Exception Float Integer Long Math Number Object Package Pair Process Runtime Runnable SecurityManager Short StackTraceElement StrictMath String StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void Annotation Any BooleanArray ByteArray Char CharArray DeprecationLevel DoubleArray Enum FloatArray Function Int IntArray Lazy LazyThreadSafetyMode LongArray Nothing ShortArray Unit"),intendSwitch:!1,indentStatements:!1,multiLineStrings:!0,number:/^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+(\.\d+)?|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i,blockKeywords:e("catch class do else finally for if where try while enum"),defKeywords:e("class val var object interface fun"),atoms:e("true false null this"),hooks:{"@":function(e){return e.eatWhile(/[\w\$_]/),"meta"},"*":function(e,t){return"."==t.prevToken?"variable":"operator"},'"':function(e,t){var a;return t.tokenize=(a=e.match('""'),function(e,t){for(var n,r=!1,o=!1;!e.eol();){if(!a&&!r&&e.match('"')){o=!0;break}if(a&&e.match('"""')){o=!0;break}n=e.next(),!r&&"$"==n&&e.match("{")&&e.skipTo("}"),r=!r&&"\\"==n&&!a}return!o&&a||(t.tokenize=null),"string"}),t.tokenize(e,t)},"/":function(e,t){return!!e.eat("*")&&(t.tokenize=v(1),t.tokenize(e,t))},indent:function(e,t,n,r){var o=n&&n.charAt(0);return"}"!=e.prevToken&&")"!=e.prevToken||""!=n?"operator"==e.prevToken&&"}"!=n&&"}"!=e.context.type||"variable"==e.prevToken&&"."==o||("}"==e.prevToken||")"==e.prevToken)&&"."==o?2*r+t.indented:t.align&&"}"==t.type?t.indented+(e.context.type==(n||"").charAt(0)?0:r):void 0:e.indented}},modeProps:{closeBrackets:{triples:'"'}}}),b(["x-shader/x-vertex","x-shader/x-fragment"],{name:"clike",keywords:e("sampler1D sampler2D sampler3D samplerCube sampler1DShadow sampler2DShadow const attribute uniform varying break continue discard return for while do if else struct in out inout"),types:e("float int bool void vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 mat2 mat3 mat4"),blockKeywords:e("for while do if else struct"),builtin:e("radians degrees sin cos tan asin acos atan pow exp log exp2 sqrt inversesqrt abs sign floor ceil fract mod min max clamp mix step smoothstep length distance dot cross normalize ftransform faceforward reflect refract matrixCompMult lessThan lessThanEqual greaterThan greaterThanEqual equal notEqual any all not texture1D texture1DProj texture1DLod texture1DProjLod texture2D texture2DProj texture2DLod texture2DProjLod texture3D texture3DProj texture3DLod texture3DProjLod textureCube textureCubeLod shadow1D shadow2D shadow1DProj shadow2DProj shadow1DLod shadow2DLod shadow1DProjLod shadow2DProjLod dFdx dFdy fwidth noise1 noise2 noise3 noise4"),atoms:e("true false gl_FragColor gl_SecondaryColor gl_Normal gl_Vertex gl_MultiTexCoord0 gl_MultiTexCoord1 gl_MultiTexCoord2 gl_MultiTexCoord3 gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6 gl_MultiTexCoord7 gl_FogCoord gl_PointCoord gl_Position gl_PointSize gl_ClipVertex gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor gl_TexCoord gl_FogFragCoord gl_FragCoord gl_FrontFacing gl_FragData gl_FragDepth gl_ModelViewMatrix gl_ProjectionMatrix gl_ModelViewProjectionMatrix gl_TextureMatrix gl_NormalMatrix gl_ModelViewMatrixInverse gl_ProjectionMatrixInverse gl_ModelViewProjectionMatrixInverse gl_TextureMatrixTranspose gl_ModelViewMatrixInverseTranspose gl_ProjectionMatrixInverseTranspose gl_ModelViewProjectionMatrixInverseTranspose gl_TextureMatrixInverseTranspose gl_NormalScale gl_DepthRange gl_ClipPlane gl_Point gl_FrontMaterial gl_BackMaterial gl_LightSource gl_LightModel gl_FrontLightModelProduct gl_BackLightModelProduct gl_TextureColor gl_EyePlaneS gl_EyePlaneT gl_EyePlaneR gl_EyePlaneQ gl_FogParameters gl_MaxLights gl_MaxClipPlanes gl_MaxTextureUnits gl_MaxTextureCoords gl_MaxVertexAttribs gl_MaxVertexUniformComponents gl_MaxVaryingFloats gl_MaxVertexTextureImageUnits gl_MaxTextureImageUnits gl_MaxFragmentUniformComponents gl_MaxCombineTextureImageUnits gl_MaxDrawBuffers"),indentSwitch:!1,hooks:{"#":d},modeProps:{fold:["brace","include"]}}),b("text/x-nesc",{name:"clike",keywords:e(t+" as atomic async call command component components configuration event generic implementation includes interface module new norace nx_struct nx_union post provides signal task uses abstract extends"),types:l,blockKeywords:e(c),atoms:e("null true false"),hooks:{"#":d},modeProps:{fold:["brace","include"]}}),b("text/x-objectivec",{name:"clike",keywords:e(t+" "+r),types:s,builtin:e(o),blockKeywords:e(c+" @synthesize @try @catch @finally @autoreleasepool @synchronized"),defKeywords:e(u+" @interface @implementation @protocol @class"),dontIndentStatements:/^@.*$/,typeFirstDefinitions:!0,atoms:e("YES NO NULL Nil nil true false nullptr"),isReservedIdentifier:p,hooks:{"#":d,"*":f},modeProps:{fold:["brace","include"]}}),b("text/x-objectivec++",{name:"clike",keywords:e(t+" "+r+" "+n),types:s,builtin:e(o),blockKeywords:e(c+" @synthesize @try @catch @finally @autoreleasepool @synchronized class try catch"),defKeywords:e(u+" @interface @implementation @protocol @class class namespace"),dontIndentStatements:/^@.*$|^template$/,typeFirstDefinitions:!0,atoms:e("YES NO NULL Nil nil true false nullptr"),isReservedIdentifier:p,hooks:{"#":d,"*":f,u:h,U:h,L:h,R:h,0:m,1:m,2:m,3:m,4:m,5:m,6:m,7:m,8:m,9:m,token:function(e,t,n){if("variable"==n&&"("==e.peek()&&(";"==t.prevToken||null==t.prevToken||"}"==t.prevToken)&&y(e.current()))return"def"}},namespaceSeparator:"::",modeProps:{fold:["brace","include"]}}),b("text/x-squirrel",{name:"clike",keywords:e("base break clone continue const default delete enum extends function in class foreach local resume return this throw typeof yield constructor instanceof static"),types:l,blockKeywords:e("case catch class else for foreach if switch try while"),defKeywords:e("function local class"),typeFirstDefinitions:!0,atoms:e("true false null"),hooks:{"#":d},modeProps:{fold:["brace","include"]}});var w=null;b("text/x-ceylon",{name:"clike",keywords:e("abstracts alias assembly assert assign break case catch class continue dynamic else exists extends finally for function given if import in interface is let module new nonempty object of out outer package return satisfies super switch then this throw try value void while"),types:function(e){e=e.charAt(0);return e===e.toUpperCase()&&e!==e.toLowerCase()},blockKeywords:e("case catch class dynamic else finally for function if interface module new object switch try while"),defKeywords:e("class dynamic function interface module object package value"),builtin:e("abstract actual aliased annotation by default deprecated doc final formal late license native optional sealed see serializable shared suppressWarnings tagged throws variable"),isPunctuationChar:/[\[\]{}\(\),;\:\.`]/,isOperatorChar:/[+\-*&%=<>!?|^~:\/]/,numberStart:/[\d#$]/,number:/^(?:#[\da-fA-F_]+|\$[01_]+|[\d_]+[kMGTPmunpf]?|[\d_]+\.[\d_]+(?:[eE][-+]?\d+|[kMGTPmunpf]|)|)/i,multiLineStrings:!0,typeFirstDefinitions:!0,atoms:e("true false null larger smaller equal empty finished"),indentSwitch:!1,styleDefs:!1,hooks:{"@":function(e){return e.eatWhile(/[\w\$_]/),"meta"},'"':function(e,t){return t.tokenize=function a(i){return function(e,t){for(var n,r=!1,o=!1;!e.eol();){if(!r&&e.match('"')&&("single"==i||e.match('""'))){o=!0;break}if(!r&&e.match("``")){w=a(i),o=!0;break}n=e.next(),r="single"==i&&!r&&"\\"==n}return o&&(t.tokenize=null),"string"}}(e.match('""')?"triple":"single"),t.tokenize(e,t)},"`":function(e,t){return!(!w||!e.match("`"))&&(t.tokenize=w,w=null,t.tokenize(e,t))},"'":function(e){return e.eatWhile(/[\w\$_\xa1-\uffff]/),"atom"},token:function(e,t,n){if(("variable"==n||"type"==n)&&"."==t.prevToken)return"variable-2"}},modeProps:{fold:["brace","import"],closeBrackets:{triples:'"'}}})}); -------------------------------------------------------------------------------- /examples/text_editor/ui/js/css.min.js: -------------------------------------------------------------------------------- 1 | !function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(T){"use strict";function e(e){for(var t={},r=0;r*\/]/.test(r)?(a="select-op",null):"."==r&&e.match(/^-?[_a-z][_a-z0-9-]*/i)?a="qualifier":/[:;{}\[\]\(\)]/.test(r)?v(null,r):e.match(/^[\w-.]+(?=\()/)?(/^(url(-prefix)?|domain|regexp)$/i.test(e.current())&&(t.tokenize=z),a="variable","variable callee"):/[\w\\\-]/.test(r)?(e.eatWhile(/[\w\\\-]/),a="word","property"):a=null})(e,t);return r&&"object"==typeof r&&(a=r[1],r=r[0]),i=r,"comment"!=a&&(t.state=_[t.state](a,e,t)),i},indent:function(e,t){var e=e.context,t=t&&t.charAt(0),r=e.indent;return(e="prop"!=e.type||"}"!=t&&")"!=t?e:e.prev).prev&&("}"!=t||"block"!=e.type&&"top"!=e.type&&"interpolation"!=e.type&&"restricted_atBlock"!=e.type?(")"!=t||"parens"!=e.type&&"atBlock_parens"!=e.type)&&("{"!=t||"at"!=e.type&&"atBlock"!=e.type)||(r=Math.max(0,e.indent-n)):r=(e=e.prev).indent),r},electricChars:"}",blockCommentStart:"/*",blockCommentEnd:"*/",blockCommentContinue:" * ",lineComment:k,fold:"brace"}});var t=["domain","regexp","url","url-prefix"],r=e(t),o=["all","aural","braille","handheld","print","projection","screen","tty","tv","embossed"],i=e(o),a=["width","min-width","max-width","height","min-height","max-height","device-width","min-device-width","max-device-width","device-height","min-device-height","max-device-height","aspect-ratio","min-aspect-ratio","max-aspect-ratio","device-aspect-ratio","min-device-aspect-ratio","max-device-aspect-ratio","color","min-color","max-color","color-index","min-color-index","max-color-index","monochrome","min-monochrome","max-monochrome","resolution","min-resolution","max-resolution","scan","grid","orientation","device-pixel-ratio","min-device-pixel-ratio","max-device-pixel-ratio","pointer","any-pointer","hover","any-hover","prefers-color-scheme","dynamic-range","video-dynamic-range"],n=e(a),l=["landscape","portrait","none","coarse","fine","on-demand","hover","interlace","progressive","dark","light","standard","high"],s=e(l),c=["align-content","align-items","align-self","alignment-adjust","alignment-baseline","all","anchor-point","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","appearance","azimuth","backdrop-filter","backface-visibility","background","background-attachment","background-blend-mode","background-clip","background-color","background-image","background-origin","background-position","background-position-x","background-position-y","background-repeat","background-size","baseline-shift","binding","bleed","block-size","bookmark-label","bookmark-level","bookmark-state","bookmark-target","border","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","caret-color","clear","clip","color","color-profile","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","contain","content","counter-increment","counter-reset","crop","cue","cue-after","cue-before","cursor","direction","display","dominant-baseline","drop-initial-after-adjust","drop-initial-after-align","drop-initial-before-adjust","drop-initial-before-align","drop-initial-size","drop-initial-value","elevation","empty-cells","fit","fit-content","fit-position","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","float-offset","flow-from","flow-into","font","font-family","font-feature-settings","font-kerning","font-language-override","font-optical-sizing","font-size","font-size-adjust","font-stretch","font-style","font-synthesis","font-variant","font-variant-alternates","font-variant-caps","font-variant-east-asian","font-variant-ligatures","font-variant-numeric","font-variant-position","font-variation-settings","font-weight","gap","grid","grid-area","grid-auto-columns","grid-auto-flow","grid-auto-rows","grid-column","grid-column-end","grid-column-gap","grid-column-start","grid-gap","grid-row","grid-row-end","grid-row-gap","grid-row-start","grid-template","grid-template-areas","grid-template-columns","grid-template-rows","hanging-punctuation","height","hyphens","icon","image-orientation","image-rendering","image-resolution","inline-box-align","inset","inset-block","inset-block-end","inset-block-start","inset-inline","inset-inline-end","inset-inline-start","isolation","justify-content","justify-items","justify-self","left","letter-spacing","line-break","line-height","line-height-step","line-stacking","line-stacking-ruby","line-stacking-shift","line-stacking-strategy","list-style","list-style-image","list-style-position","list-style-type","margin","margin-bottom","margin-left","margin-right","margin-top","marks","marquee-direction","marquee-loop","marquee-play-count","marquee-speed","marquee-style","mask-clip","mask-composite","mask-image","mask-mode","mask-origin","mask-position","mask-repeat","mask-size","mask-type","max-block-size","max-height","max-inline-size","max-width","min-block-size","min-height","min-inline-size","min-width","mix-blend-mode","move-to","nav-down","nav-index","nav-left","nav-right","nav-up","object-fit","object-position","offset","offset-anchor","offset-distance","offset-path","offset-position","offset-rotate","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-style","overflow-wrap","overflow-x","overflow-y","padding","padding-bottom","padding-left","padding-right","padding-top","page","page-break-after","page-break-before","page-break-inside","page-policy","pause","pause-after","pause-before","perspective","perspective-origin","pitch","pitch-range","place-content","place-items","place-self","play-during","position","presentation-level","punctuation-trim","quotes","region-break-after","region-break-before","region-break-inside","region-fragment","rendering-intent","resize","rest","rest-after","rest-before","richness","right","rotate","rotation","rotation-point","row-gap","ruby-align","ruby-overhang","ruby-position","ruby-span","scale","scroll-behavior","scroll-margin","scroll-margin-block","scroll-margin-block-end","scroll-margin-block-start","scroll-margin-bottom","scroll-margin-inline","scroll-margin-inline-end","scroll-margin-inline-start","scroll-margin-left","scroll-margin-right","scroll-margin-top","scroll-padding","scroll-padding-block","scroll-padding-block-end","scroll-padding-block-start","scroll-padding-bottom","scroll-padding-inline","scroll-padding-inline-end","scroll-padding-inline-start","scroll-padding-left","scroll-padding-right","scroll-padding-top","scroll-snap-align","scroll-snap-type","shape-image-threshold","shape-inside","shape-margin","shape-outside","size","speak","speak-as","speak-header","speak-numeral","speak-punctuation","speech-rate","stress","string-set","tab-size","table-layout","target","target-name","target-new","target-position","text-align","text-align-last","text-combine-upright","text-decoration","text-decoration-color","text-decoration-line","text-decoration-skip","text-decoration-skip-ink","text-decoration-style","text-emphasis","text-emphasis-color","text-emphasis-position","text-emphasis-style","text-height","text-indent","text-justify","text-orientation","text-outline","text-overflow","text-rendering","text-shadow","text-size-adjust","text-space-collapse","text-transform","text-underline-position","text-wrap","top","touch-action","transform","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","translate","unicode-bidi","user-select","vertical-align","visibility","voice-balance","voice-duration","voice-family","voice-pitch","voice-range","voice-rate","voice-stress","voice-volume","volume","white-space","widows","width","will-change","word-break","word-spacing","word-wrap","writing-mode","z-index","clip-path","clip-rule","mask","enable-background","filter","flood-color","flood-opacity","lighting-color","stop-color","stop-opacity","pointer-events","color-interpolation","color-interpolation-filters","color-rendering","fill","fill-opacity","fill-rule","image-rendering","marker","marker-end","marker-mid","marker-start","paint-order","shape-rendering","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","text-rendering","baseline-shift","dominant-baseline","glyph-orientation-horizontal","glyph-orientation-vertical","text-anchor","writing-mode"],d=e(c),p=["accent-color","aspect-ratio","border-block","border-block-color","border-block-end","border-block-end-color","border-block-end-style","border-block-end-width","border-block-start","border-block-start-color","border-block-start-style","border-block-start-width","border-block-style","border-block-width","border-inline","border-inline-color","border-inline-end","border-inline-end-color","border-inline-end-style","border-inline-end-width","border-inline-start","border-inline-start-color","border-inline-start-style","border-inline-start-width","border-inline-style","border-inline-width","content-visibility","margin-block","margin-block-end","margin-block-start","margin-inline","margin-inline-end","margin-inline-start","overflow-anchor","overscroll-behavior","padding-block","padding-block-end","padding-block-start","padding-inline","padding-inline-end","padding-inline-start","scroll-snap-stop","scrollbar-3d-light-color","scrollbar-arrow-color","scrollbar-base-color","scrollbar-dark-shadow-color","scrollbar-face-color","scrollbar-highlight-color","scrollbar-shadow-color","scrollbar-track-color","searchfield-cancel-button","searchfield-decoration","searchfield-results-button","searchfield-results-decoration","shape-inside","zoom"],u=e(p),m=e(["font-display","font-family","src","unicode-range","font-variant","font-feature-settings","font-stretch","font-weight","font-style"]),g=e(["additive-symbols","fallback","negative","pad","prefix","range","speak-as","suffix","symbols","system"]),b=["aliceblue","antiquewhite","aqua","aquamarine","azure","beige","bisque","black","blanchedalmond","blue","blueviolet","brown","burlywood","cadetblue","chartreuse","chocolate","coral","cornflowerblue","cornsilk","crimson","cyan","darkblue","darkcyan","darkgoldenrod","darkgray","darkgreen","darkgrey","darkkhaki","darkmagenta","darkolivegreen","darkorange","darkorchid","darkred","darksalmon","darkseagreen","darkslateblue","darkslategray","darkslategrey","darkturquoise","darkviolet","deeppink","deepskyblue","dimgray","dimgrey","dodgerblue","firebrick","floralwhite","forestgreen","fuchsia","gainsboro","ghostwhite","gold","goldenrod","gray","grey","green","greenyellow","honeydew","hotpink","indianred","indigo","ivory","khaki","lavender","lavenderblush","lawngreen","lemonchiffon","lightblue","lightcoral","lightcyan","lightgoldenrodyellow","lightgray","lightgreen","lightgrey","lightpink","lightsalmon","lightseagreen","lightskyblue","lightslategray","lightslategrey","lightsteelblue","lightyellow","lime","limegreen","linen","magenta","maroon","mediumaquamarine","mediumblue","mediumorchid","mediumpurple","mediumseagreen","mediumslateblue","mediumspringgreen","mediumturquoise","mediumvioletred","midnightblue","mintcream","mistyrose","moccasin","navajowhite","navy","oldlace","olive","olivedrab","orange","orangered","orchid","palegoldenrod","palegreen","paleturquoise","palevioletred","papayawhip","peachpuff","peru","pink","plum","powderblue","purple","rebeccapurple","red","rosybrown","royalblue","saddlebrown","salmon","sandybrown","seagreen","seashell","sienna","silver","skyblue","slateblue","slategray","slategrey","snow","springgreen","steelblue","tan","teal","thistle","tomato","turquoise","violet","wheat","white","whitesmoke","yellow","yellowgreen"],h=e(b),f=["above","absolute","activeborder","additive","activecaption","afar","after-white-space","ahead","alias","all","all-scroll","alphabetic","alternate","always","amharic","amharic-abegede","antialiased","appworkspace","arabic-indic","armenian","asterisks","attr","auto","auto-flow","avoid","avoid-column","avoid-page","avoid-region","axis-pan","background","backwards","baseline","below","bidi-override","binary","bengali","blink","block","block-axis","blur","bold","bolder","border","border-box","both","bottom","break","break-all","break-word","brightness","bullets","button","buttonface","buttonhighlight","buttonshadow","buttontext","calc","cambodian","capitalize","caps-lock-indicator","caption","captiontext","caret","cell","center","checkbox","circle","cjk-decimal","cjk-earthly-branch","cjk-heavenly-stem","cjk-ideographic","clear","clip","close-quote","col-resize","collapse","color","color-burn","color-dodge","column","column-reverse","compact","condensed","conic-gradient","contain","content","contents","content-box","context-menu","continuous","contrast","copy","counter","counters","cover","crop","cross","crosshair","cubic-bezier","currentcolor","cursive","cyclic","darken","dashed","decimal","decimal-leading-zero","default","default-button","dense","destination-atop","destination-in","destination-out","destination-over","devanagari","difference","disc","discard","disclosure-closed","disclosure-open","document","dot-dash","dot-dot-dash","dotted","double","down","drop-shadow","e-resize","ease","ease-in","ease-in-out","ease-out","element","ellipse","ellipsis","embed","end","ethiopic","ethiopic-abegede","ethiopic-abegede-am-et","ethiopic-abegede-gez","ethiopic-abegede-ti-er","ethiopic-abegede-ti-et","ethiopic-halehame-aa-er","ethiopic-halehame-aa-et","ethiopic-halehame-am-et","ethiopic-halehame-gez","ethiopic-halehame-om-et","ethiopic-halehame-sid-et","ethiopic-halehame-so-et","ethiopic-halehame-ti-er","ethiopic-halehame-ti-et","ethiopic-halehame-tig","ethiopic-numeric","ew-resize","exclusion","expanded","extends","extra-condensed","extra-expanded","fantasy","fast","fill","fill-box","fixed","flat","flex","flex-end","flex-start","footnotes","forwards","from","geometricPrecision","georgian","grayscale","graytext","grid","groove","gujarati","gurmukhi","hand","hangul","hangul-consonant","hard-light","hebrew","help","hidden","hide","higher","highlight","highlighttext","hiragana","hiragana-iroha","horizontal","hsl","hsla","hue","hue-rotate","icon","ignore","inactiveborder","inactivecaption","inactivecaptiontext","infinite","infobackground","infotext","inherit","initial","inline","inline-axis","inline-block","inline-flex","inline-grid","inline-table","inset","inside","intrinsic","invert","italic","japanese-formal","japanese-informal","justify","kannada","katakana","katakana-iroha","keep-all","khmer","korean-hangul-formal","korean-hanja-formal","korean-hanja-informal","landscape","lao","large","larger","left","level","lighter","lighten","line-through","linear","linear-gradient","lines","list-item","listbox","listitem","local","logical","loud","lower","lower-alpha","lower-armenian","lower-greek","lower-hexadecimal","lower-latin","lower-norwegian","lower-roman","lowercase","ltr","luminosity","malayalam","manipulation","match","matrix","matrix3d","media-play-button","media-slider","media-sliderthumb","media-volume-slider","media-volume-sliderthumb","medium","menu","menulist","menulist-button","menutext","message-box","middle","min-intrinsic","mix","mongolian","monospace","move","multiple","multiple_mask_images","multiply","myanmar","n-resize","narrower","ne-resize","nesw-resize","no-close-quote","no-drop","no-open-quote","no-repeat","none","normal","not-allowed","nowrap","ns-resize","numbers","numeric","nw-resize","nwse-resize","oblique","octal","opacity","open-quote","optimizeLegibility","optimizeSpeed","oriya","oromo","outset","outside","outside-shape","overlay","overline","padding","padding-box","painted","page","paused","persian","perspective","pinch-zoom","plus-darker","plus-lighter","pointer","polygon","portrait","pre","pre-line","pre-wrap","preserve-3d","progress","push-button","radial-gradient","radio","read-only","read-write","read-write-plaintext-only","rectangle","region","relative","repeat","repeating-linear-gradient","repeating-radial-gradient","repeating-conic-gradient","repeat-x","repeat-y","reset","reverse","rgb","rgba","ridge","right","rotate","rotate3d","rotateX","rotateY","rotateZ","round","row","row-resize","row-reverse","rtl","run-in","running","s-resize","sans-serif","saturate","saturation","scale","scale3d","scaleX","scaleY","scaleZ","screen","scroll","scrollbar","scroll-position","se-resize","searchfield","searchfield-cancel-button","searchfield-decoration","searchfield-results-button","searchfield-results-decoration","self-start","self-end","semi-condensed","semi-expanded","separate","sepia","serif","show","sidama","simp-chinese-formal","simp-chinese-informal","single","skew","skewX","skewY","skip-white-space","slide","slider-horizontal","slider-vertical","sliderthumb-horizontal","sliderthumb-vertical","slow","small","small-caps","small-caption","smaller","soft-light","solid","somali","source-atop","source-in","source-out","source-over","space","space-around","space-between","space-evenly","spell-out","square","square-button","start","static","status-bar","stretch","stroke","stroke-box","sub","subpixel-antialiased","svg_masks","super","sw-resize","symbolic","symbols","system-ui","table","table-caption","table-cell","table-column","table-column-group","table-footer-group","table-header-group","table-row","table-row-group","tamil","telugu","text","text-bottom","text-top","textarea","textfield","thai","thick","thin","threeddarkshadow","threedface","threedhighlight","threedlightshadow","threedshadow","tibetan","tigre","tigrinya-er","tigrinya-er-abegede","tigrinya-et","tigrinya-et-abegede","to","top","trad-chinese-formal","trad-chinese-informal","transform","translate","translate3d","translateX","translateY","translateZ","transparent","ultra-condensed","ultra-expanded","underline","unidirectional-pan","unset","up","upper-alpha","upper-armenian","upper-greek","upper-hexadecimal","upper-latin","upper-norwegian","upper-roman","uppercase","urdu","url","var","vertical","vertical-text","view-box","visible","visibleFill","visiblePainted","visibleStroke","visual","w-resize","wait","wave","wider","window","windowframe","windowtext","words","wrap","wrap-reverse","x-large","x-small","xor","xx-large","xx-small"],k=e(f),t=t.concat(o).concat(a).concat(l).concat(c).concat(p).concat(b).concat(f);function y(e,t){for(var r,o=!1;null!=(r=e.next());){if(o&&"/"==r){t.tokenize=null;break}o="*"==r}return["comment","comment"]}T.registerHelper("hintWords","css",t),T.defineMIME("text/css",{documentTypes:r,mediaTypes:i,mediaFeatures:n,mediaValueKeywords:s,propertyKeywords:d,nonStandardPropertyKeywords:u,fontProperties:m,counterDescriptors:g,colorKeywords:h,valueKeywords:k,tokenHooks:{"/":function(e,t){return!!e.eat("*")&&(t.tokenize=y)(e,t)}},name:"css"}),T.defineMIME("text/x-scss",{mediaTypes:i,mediaFeatures:n,mediaValueKeywords:s,propertyKeywords:d,nonStandardPropertyKeywords:u,colorKeywords:h,valueKeywords:k,fontProperties:m,allowNested:!0,lineComment:"//",tokenHooks:{"/":function(e,t){return e.eat("/")?(e.skipToEnd(),["comment","comment"]):e.eat("*")?(t.tokenize=y)(e,t):["operator","operator"]},":":function(e){return!!e.match(/^\s*\{/,!1)&&[null,null]},$:function(e){return e.match(/^[\w-]+/),e.match(/^\s*:/,!1)?["variable-2","variable-definition"]:["variable-2","variable"]},"#":function(e){return!!e.eat("{")&&[null,"interpolation"]}},name:"css",helperType:"scss"}),T.defineMIME("text/x-less",{mediaTypes:i,mediaFeatures:n,mediaValueKeywords:s,propertyKeywords:d,nonStandardPropertyKeywords:u,colorKeywords:h,valueKeywords:k,fontProperties:m,allowNested:!0,lineComment:"//",tokenHooks:{"/":function(e,t){return e.eat("/")?(e.skipToEnd(),["comment","comment"]):e.eat("*")?(t.tokenize=y)(e,t):["operator","operator"]},"@":function(e){return e.eat("{")?[null,"interpolation"]:!e.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/i,!1)&&(e.eatWhile(/[\w\\\-]/),e.match(/^\s*:/,!1)?["variable-2","variable-definition"]:["variable-2","variable"])},"&":function(){return["atom","atom"]}},name:"css",helperType:"less"}),T.defineMIME("text/x-gss",{documentTypes:r,mediaTypes:i,mediaFeatures:n,propertyKeywords:d,nonStandardPropertyKeywords:u,fontProperties:m,counterDescriptors:g,colorKeywords:h,valueKeywords:k,supportsAtComponent:!0,tokenHooks:{"/":function(e,t){return!!e.eat("*")&&(t.tokenize=y)(e,t)}},name:"css",helperType:"gss"})}); -------------------------------------------------------------------------------- /examples/text_editor/ui/js/javascript.min.js: -------------------------------------------------------------------------------- 1 | !function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(rt){"use strict";rt.defineMode("javascript",function(e,l){var t,r,O,P,f=e.indentUnit,N=l.statementIndent,U=l.jsonld,o=l.json||U,W=!1!==l.trackScope,u=l.typescript,B=l.wordCharacters||/[\w$\xa1-\uffff]/,F=(e=n("keyword a"),t=n("keyword b"),r=n("keyword c"),O=n("keyword d"),P=n("operator"),{if:n("if"),while:e,with:e,else:t,do:t,try:t,finally:t,return:O,break:O,continue:O,new:n("new"),delete:r,void:r,throw:r,debugger:n("debugger"),var:n("var"),const:n("var"),let:n("var"),function:n("function"),catch:n("catch"),for:n("for"),switch:n("switch"),case:n("case"),default:n("default"),in:P,typeof:P,instanceof:P,true:e={type:"atom",style:"atom"},false:e,null:e,undefined:e,NaN:e,Infinity:e,this:n("this"),class:n("class"),super:n("atom"),yield:r,export:n("export"),import:n("import"),extends:r,await:r});function n(e){return{type:e,style:"keyword"}}var H,D,G=/[+\-*&%=<>!?|~^@]/,J=/^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;function i(e,t,r){return H=e,D=r,t}function d(e,t){var a,r=e.next();if('"'==r||"'"==r)return t.tokenize=(a=r,function(e,t){var r,n=!1;if(U&&"@"==e.peek()&&e.match(J))return t.tokenize=d,i("jsonld-keyword","meta");for(;null!=(r=e.next())&&(r!=a||n);)n=!n&&"\\"==r;return n||(t.tokenize=d),i("string","string")}),t.tokenize(e,t);if("."==r&&e.match(/^\d[\d_]*(?:[eE][+\-]?[\d_]+)?/))return i("number","number");if("."==r&&e.match(".."))return i("spread","meta");if(/[\[\]{}\(\),;\:\.]/.test(r))return i(r);if("="==r&&e.eat(">"))return i("=>","operator");if("0"==r&&e.match(/^(?:x[\dA-Fa-f_]+|o[0-7_]+|b[01_]+)n?/))return i("number","number");if(/\d/.test(r))return e.match(/^[\d_]*(?:n|(?:\.[\d_]*)?(?:[eE][+\-]?[\d_]+)?)?/),i("number","number");if("/"==r)return e.eat("*")?(t.tokenize=K)(e,t):e.eat("/")?(e.skipToEnd(),i("comment","comment")):tt(e,t,1)?(function(e){for(var t,r=!1,n=!1;null!=(t=e.next());){if(!r){if("/"==t&&!n)return;"["==t?n=!0:n&&"]"==t&&(n=!1)}r=!r&&"\\"==t}}(e),e.match(/^\b(([gimyus])(?![gimyus]*\2))+\b/),i("regexp","string-2")):(e.eat("="),i("operator","operator",e.current()));if("`"==r)return(t.tokenize=L)(e,t);if("#"==r&&"!"==e.peek())return e.skipToEnd(),i("meta","meta");if("#"==r&&e.eatWhile(B))return i("variable","property");if("<"==r&&e.match("!--")||"-"==r&&e.match("->")&&!/\S/.test(e.string.slice(0,e.start)))return e.skipToEnd(),i("comment","comment");if(G.test(r))return">"==r&&t.lexical&&">"==t.lexical.type||(e.eat("=")?"!"!=r&&"="!=r||e.eat("="):/[<>*+\-|&?]/.test(r)&&(e.eat(r),">"==r&&e.eat(r))),"?"==r&&e.eat(".")?i("."):i("operator","operator",e.current());if(B.test(r)){e.eatWhile(B);r=e.current();if("."!=t.lastType){if(F.propertyIsEnumerable(r))return i((t=F[r]).type,t.style,r);if("async"==r&&e.match(/^(\s|\/\*([^*]|\*(?!\/))*?\*\/)*[\[\(\w]/,!1))return i("async","keyword",r)}return i("variable","variable",r)}}function K(e,t){for(var r,n=!1;r=e.next();){if("/"==r&&n){t.tokenize=d;break}n="*"==r}return i("comment","comment")}function L(e,t){for(var r,n=!1;null!=(r=e.next());){if(!n&&("`"==r||"$"==r&&e.eat("{"))){t.tokenize=d;break}n=!n&&"\\"==r}return i("quasi","string-2",e.current())}function Q(e,t){t.fatArrowAt&&(t.fatArrowAt=null);var r=e.string.indexOf("=>",e.start);if(!(r<0)){!u||(n=/:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(e.string.slice(e.start,r)))&&(r=n.index);for(var n,a=0,i=!1,o=r-1;0<=o;--o){var c=e.string.charAt(o),s="([{}])".indexOf(c);if(0<=s&&s<3){if(!a){++o;break}if(0==--a){"("==c&&(i=!0);break}}else if(3<=s&&s<6)++a;else if(B.test(c))i=!0;else if(/["'\/`]/.test(c))for(;;--o){if(0==o)return;if(e.string.charAt(o-1)==c&&"\\"!=e.string.charAt(o-2)){o--;break}}else if(i&&!a){++o;break}}i&&!a&&(t.fatArrowAt=o)}}var R={atom:!0,number:!0,variable:!0,string:!0,regexp:!0,this:!0,import:!0,"jsonld-keyword":!0};function X(e,t,r,n,a,i){this.indented=e,this.column=t,this.type=r,this.prev=a,this.info=i,null!=n&&(this.align=n)}function Y(e,t,r,n,a){var i=e.cc;for(c.state=e,c.stream=a,c.marked=null,c.cc=i,c.style=t,e.lexical.hasOwnProperty("align")||(e.lexical.align=!0);;)if((i.length?i.pop():o?x:b)(r,n)){for(;i.length&&i[i.length-1].lex;)i.pop()();return c.marked?c.marked:"variable"==r&&function(e,t){if(W){for(var r=e.localVars;r;r=r.next)if(r.name==t)return 1;for(var n=e.context;n;n=n.prev)for(r=n.vars;r;r=r.next)if(r.name==t)return 1}}(e,n)?"variable-2":t}}var c={state:null,column:null,marked:null,cc:null};function s(){for(var e=arguments.length-1;0<=e;e--)c.cc.push(arguments[e])}function p(){return s.apply(null,arguments),!0}function Z(e,t){for(var r=t;r;r=r.next)if(r.name==e)return 1}function a(e){var t=c.state;if(c.marked="def",W){if(t.context)if("var"==t.lexical.info&&t.context&&t.context.block){var r=function e(t,r){{var n;return r?r.block?(n=e(t,r.prev))?n==r.prev?r:new te(n,r.vars,!0):null:Z(t,r.vars)?r:new te(r.prev,new re(t,r.vars),!1):null}}(e,t.context);if(null!=r)return void(t.context=r)}else if(!Z(e,t.localVars))return void(t.localVars=new re(e,t.localVars));l.globalVars&&!Z(e,t.globalVars)&&(t.globalVars=new re(e,t.globalVars))}}function ee(e){return"public"==e||"private"==e||"protected"==e||"abstract"==e||"readonly"==e}function te(e,t,r){this.prev=e,this.vars=t,this.block=r}function re(e,t){this.name=e,this.next=t}var ne=new re("this",new re("arguments",null));function m(){c.state.context=new te(c.state.context,c.state.localVars,!1),c.state.localVars=ne}function ae(){c.state.context=new te(c.state.context,c.state.localVars,!0),c.state.localVars=null}function k(){c.state.localVars=c.state.context.vars,c.state.context=c.state.context.prev}function v(n,a){function e(){var e=c.state,t=e.indented;if("stat"==e.lexical.type)t=e.lexical.indented;else for(var r=e.lexical;r&&")"==r.type&&r.align;r=r.prev)t=r.indented;e.lexical=new X(t,c.stream.column(),n,null,e.lexical,a)}return e.lex=!0,e}function y(){var e=c.state;e.lexical.prev&&(")"==e.lexical.type&&(e.indented=e.lexical.indented),e.lexical=e.lexical.prev)}function w(r){return function e(t){return t==r?p():";"==r||"}"==t||")"==t||"]"==t?s():p(e)}}function b(e,t){return"var"==e?p(v("vardef",t),qe,w(";"),y):"keyword a"==e?p(v("form"),oe,b,y):"keyword b"==e?p(v("form"),b,y):"keyword d"==e?c.stream.match(/^\s*$/,!1)?p():p(v("stat"),g,w(";"),y):"debugger"==e?p(w(";")):"{"==e?p(v("}"),ae,be,y,k):";"==e?p():"if"==e?("else"==c.state.lexical.info&&c.state.cc[c.state.cc.length-1]==y&&c.state.cc.pop()(),p(v("form"),oe,b,y,Oe)):"function"==e?p(q):"for"==e?p(v("form"),ae,Pe,b,k,y):"class"==e||u&&"interface"==t?(c.marked="keyword",p(v("form","class"==e?e:t),Fe,y)):"variable"==e?u&&"declare"==t?(c.marked="keyword",p(b)):u&&("module"==t||"enum"==t||"type"==t)&&c.stream.match(/^\s*\w/,!1)?(c.marked="keyword","enum"==t?p(Ze):"type"==t?p(We,w("operator"),z,w(";")):p(v("form"),T,w("{"),v("}"),be,y,y)):u&&"namespace"==t?(c.marked="keyword",p(v("form"),x,b,y)):u&&"abstract"==t?(c.marked="keyword",p(b)):p(v("stat"),me):"switch"==e?p(v("form"),oe,w("{"),v("}","switch"),ae,be,y,y,k):"case"==e?p(x,w(":")):"default"==e?p(w(":")):"catch"==e?p(v("form"),m,ie,b,y,k):"export"==e?p(v("stat"),Ge,y):"import"==e?p(v("stat"),Ke,y):"async"==e?p(b):"@"==t?p(x,b):s(v("stat"),x,w(";"),y)}function ie(e){if("("==e)return p(S,w(")"))}function x(e,t){return ce(e,t,!1)}function h(e,t){return ce(e,t,!0)}function oe(e){return"("!=e?s():p(v(")"),g,w(")"),y)}function ce(e,t,r){if(c.state.fatArrowAt==c.stream.start){var n=r?fe:le;if("("==e)return p(m,v(")"),V(S,")"),y,w("=>"),n,k);if("variable"==e)return s(m,T,w("=>"),n,k)}var a,n=r?M:j;return R.hasOwnProperty(e)?p(n):"function"==e?p(q,n):"class"==e||u&&"interface"==t?(c.marked="keyword",p(v("form"),Be,y)):"keyword c"==e||"async"==e?p(r?h:x):"("==e?p(v(")"),g,w(")"),y,n):"operator"==e||"spread"==e?p(r?h:x):"["==e?p(v("]"),Ye,y,n):"{"==e?we(ve,"}",null,n):"quasi"==e?s(se,n):"new"==e?p((a=r,function(e){return"."==e?p(a?pe:de):"variable"==e&&u?p(Ie,a?M:j):s(a?h:x)})):p()}function g(e){return e.match(/[;\}\)\],]/)?s():s(x)}function j(e,t){return","==e?p(g):M(e,t,!1)}function M(e,t,r){var n=0==r?j:M,a=0==r?x:h;return"=>"==e?p(m,r?fe:le,k):"operator"==e?/\+\+|--/.test(t)||u&&"!"==t?p(n):u&&"<"==t&&c.stream.match(/^([^<>]|<[^<>]*>)*>\s*\(/,!1)?p(v(">"),V(z,">"),y,n):"?"==t?p(x,w(":"),a):p(a):"quasi"==e?s(se,n):";"!=e?"("==e?we(h,")","call",n):"."==e?p(ke,n):"["==e?p(v("]"),g,w("]"),y,n):u&&"as"==t?(c.marked="keyword",p(z,n)):"regexp"==e?(c.state.lastType=c.marked="operator",c.stream.backUp(c.stream.pos-c.stream.start-1),p(a)):void 0:void 0}function se(e,t){return"quasi"!=e?s():"${"!=t.slice(t.length-2)?p(se):p(g,ue)}function ue(e){if("}"==e)return c.marked="string-2",c.state.tokenize=L,p(se)}function le(e){return Q(c.stream,c.state),s("{"==e?b:x)}function fe(e){return Q(c.stream,c.state),s("{"==e?b:h)}function de(e,t){if("target"==t)return c.marked="keyword",p(j)}function pe(e,t){if("target"==t)return c.marked="keyword",p(M)}function me(e){return":"==e?p(y,b):s(j,w(";"),y)}function ke(e){if("variable"==e)return c.marked="property",p()}function ve(e,t){return"async"==e?(c.marked="property",p(ve)):"variable"!=e&&"keyword"!=c.style?"number"==e||"string"==e?(c.marked=U?"property":c.style+" property",p(A)):"jsonld-keyword"==e?p(A):u&&ee(t)?(c.marked="keyword",p(ve)):"["==e?p(x,E,w("]"),A):"spread"==e?p(h,A):"*"==t?(c.marked="keyword",p(ve)):":"==e?s(A):void 0:(c.marked="property","get"==t||"set"==t?p(ye):(u&&c.state.fatArrowAt==c.stream.start&&(e=c.stream.match(/^\s*:\s*/,!1))&&(c.state.fatArrowAt=c.stream.pos+e[0].length),p(A)))}function ye(e){return"variable"!=e?s(A):(c.marked="property",p(q))}function A(e){return":"==e?p(h):"("==e?s(q):void 0}function V(n,a,i){function o(e,t){var r;return(i?-1"),z):"quasi"==e?s(Ve,I):void 0}function je(e){if("=>"==e)return p(z)}function Me(e){return e.match(/[\}\)\]]/)?p():","==e||";"==e?p(Me):s(Ae,Me)}function Ae(e,t){return"variable"==e||"keyword"==c.style?(c.marked="property",p(Ae)):"?"==t||"number"==e||"string"==e?p(Ae):":"==e?p(z):"["==e?p(w("variable"),xe,w("]"),Ae):"("==e?s(C,Ae):e.match(/[;\}\)\],]/)?void 0:p()}function Ve(e,t){return"quasi"!=e?s():"${"!=t.slice(t.length-2)?p(Ve):p(z,Ee)}function Ee(e){if("}"==e)return c.marked="string-2",c.state.tokenize=L,p(Ve)}function ze(e,t){return"variable"==e&&c.stream.match(/^\s*[?:]/,!1)||"?"==t?p(ze):":"==e?p(z):"spread"==e?p(ze):s(z)}function I(e,t){return"<"==t?p(v(">"),V(z,">"),y,I):"|"==t||"."==e||"&"==t?p(z):"["==e?p(z,w("]"),I):"extends"==t||"implements"==t?(c.marked="keyword",p(z)):"?"==t?p(z,w(":"),z):void 0}function Ie(e,t){if("<"==t)return p(v(">"),V(z,">"),y,I)}function Te(){return s(z,$e)}function $e(e,t){if("="==t)return p(z)}function qe(e,t){return"enum"==t?(c.marked="keyword",p(Ze)):s(T,E,$,_e)}function T(e,t){return u&&ee(t)?(c.marked="keyword",p(T)):"variable"==e?(a(t),p()):"spread"==e?p(T):"["==e?we(Se,"]"):"{"==e?we(Ce,"}"):void 0}function Ce(e,t){return"variable"!=e||c.stream.match(/^\s*:/,!1)?("variable"==e&&(c.marked="property"),"spread"==e?p(T):"}"==e?s():"["==e?p(x,w("]"),w(":"),Ce):p(w(":"),T,$)):(a(t),p($))}function Se(){return s(T,$)}function $(e,t){if("="==t)return p(h)}function _e(e){if(","==e)return p(qe)}function Oe(e,t){if("keyword b"==e&&"else"==t)return p(v("form","else"),b,y)}function Pe(e,t){return"await"==t?p(Pe):"("==e?p(v(")"),Ne,y):void 0}function Ne(e){return"var"==e?p(qe,Ue):("variable"==e?p:s)(Ue)}function Ue(e,t){return")"==e?p():";"==e?p(Ue):"in"==t||"of"==t?(c.marked="keyword",p(x,Ue)):s(x,Ue)}function q(e,t){return"*"==t?(c.marked="keyword",p(q)):"variable"==e?(a(t),p(q)):"("==e?p(m,v(")"),V(S,")"),y,he,b,k):u&&"<"==t?p(v(">"),V(Te,">"),y,q):void 0}function C(e,t){return"*"==t?(c.marked="keyword",p(C)):"variable"==e?(a(t),p(C)):"("==e?p(m,v(")"),V(S,")"),y,he,k):u&&"<"==t?p(v(">"),V(Te,">"),y,C):void 0}function We(e,t){return"keyword"==e||"variable"==e?(c.marked="type",p(We)):"<"==t?p(v(">"),V(Te,">"),y):void 0}function S(e,t){return"@"==t&&p(x,S),"spread"==e?p(S):u&&ee(t)?(c.marked="keyword",p(S)):u&&"this"==e?p(E,$):s(T,E,$)}function Be(e,t){return("variable"==e?Fe:He)(e,t)}function Fe(e,t){if("variable"==e)return a(t),p(He)}function He(e,t){return"<"==t?p(v(">"),V(Te,">"),y,He):"extends"==t||"implements"==t||u&&","==e?("implements"==t&&(c.marked="keyword"),p(u?z:x,He)):"{"==e?p(v("}"),_,y):void 0}function _(e,t){return"async"==e||"variable"==e&&("static"==t||"get"==t||"set"==t||u&&ee(t))&&c.stream.match(/^\s+[\w$\xa1-\uffff]/,!1)?(c.marked="keyword",p(_)):"variable"==e||"keyword"==c.style?(c.marked="property",p(De,_)):"number"==e||"string"==e?p(De,_):"["==e?p(x,E,w("]"),De,_):"*"==t?(c.marked="keyword",p(_)):u&&"("==e?s(C,_):";"==e||","==e?p(_):"}"==e?p():"@"==t?p(x,_):void 0}function De(e,t){if("!"==t)return p(De);if("?"==t)return p(De);if(":"==e)return p(z,$);if("="==t)return p(h);e=c.state.lexical.prev;return s(e&&"interface"==e.info?C:q)}function Ge(e,t){return"*"==t?(c.marked="keyword",p(Xe,w(";"))):"default"==t?(c.marked="keyword",p(x,w(";"))):"{"==e?p(V(Je,"}"),Xe,w(";")):s(b)}function Je(e,t){return"as"==t?(c.marked="keyword",p(w("variable"))):"variable"==e?s(h,Je):void 0}function Ke(e){return"string"==e?p():"("==e?s(x):"."==e?s(j):s(Le,Qe,Xe)}function Le(e,t){return"{"==e?we(Le,"}"):("variable"==e&&a(t),"*"==t&&(c.marked="keyword"),p(Re))}function Qe(e){if(","==e)return p(Le,Qe)}function Re(e,t){if("as"==t)return c.marked="keyword",p(Le)}function Xe(e,t){if("from"==t)return c.marked="keyword",p(x)}function Ye(e){return"]"==e?p():s(V(h,"]"))}function Ze(){return s(v("form"),T,w("{"),v("}"),V(et,"}"),y,y)}function et(){return s(T,$)}function tt(e,t,r){return t.tokenize==d&&/^(?:operator|sof|keyword [bcd]|case|new|export|default|spread|[\[{}\(,;:]|=>)$/.test(t.lastType)||"quasi"==t.lastType&&/\{\s*$/.test(e.string.slice(0,e.pos-(r||0)))}return m.lex=ae.lex=!0,y.lex=k.lex=!0,{startState:function(e){e={tokenize:d,lastType:"sof",cc:[],lexical:new X((e||0)-f,0,"block",!1),localVars:l.localVars,context:l.localVars&&new te(null,null,!1),indented:e||0};return l.globalVars&&"object"==typeof l.globalVars&&(e.globalVars=l.globalVars),e},token:function(e,t){if(e.sol()&&(t.lexical.hasOwnProperty("align")||(t.lexical.align=!1),t.indented=e.indentation(),Q(e,t)),t.tokenize!=K&&e.eatSpace())return null;var r=t.tokenize(e,t);return"comment"==H?r:(t.lastType="operator"!=H||"++"!=D&&"--"!=D?H:"incdec",Y(t,r,H,D,e))},indent:function(e,t){if(e.tokenize==K||e.tokenize==L)return rt.Pass;if(e.tokenize!=d)return 0;var r,n=t&&t.charAt(0),a=e.lexical;if(!/^\s*else\b/.test(t))for(var i=e.cc.length-1;0<=i;--i){var o=e.cc[i];if(o==y)a=a.prev;else if(o!=Oe&&o!=k)break}for(;("stat"==a.type||"form"==a.type)&&("}"==n||(r=e.cc[e.cc.length-1])&&(r==j||r==M)&&!/^[,\.=+\-*:?[\(]/.test(t));)a=a.prev;var c,s=(a=N&&")"==a.type&&"stat"==a.prev.type?a.prev:a).type,u=n==s;return"vardef"==s?a.indented+("operator"==e.lastType||","==e.lastType?a.info.length+1:0):"form"==s&&"{"==n?a.indented:"form"==s?a.indented+f:"stat"==s?a.indented+(s=t,"operator"==(c=e).lastType||","==c.lastType||G.test(s.charAt(0))||/[,.]/.test(s.charAt(0))?N||f:0):"switch"!=a.info||u||0==l.doubleIndentSwitch?a.align?a.column+(u?0:1):a.indented+(u?0:f):a.indented+(/^(?:case|default)\b/.test(t)?f:2*f)},electricInput:/^\s*(?:case .*?:|default:|\{|\})$/,blockCommentStart:o?null:"/*",blockCommentEnd:o?null:"*/",blockCommentContinue:o?null:" * ",lineComment:o?null:"//",fold:"brace",closeBrackets:"()[]{}''\"\"``",helperType:o?"json":"javascript",jsonldMode:U,jsonMode:o,expressionAllowed:tt,skipExpression:function(e){Y(e,"atom","atom","true",new rt.StringStream("",2,null))}}}),rt.registerHelper("wordChars","javascript",/[\w$]/),rt.defineMIME("text/javascript","javascript"),rt.defineMIME("text/ecmascript","javascript"),rt.defineMIME("application/javascript","javascript"),rt.defineMIME("application/x-javascript","javascript"),rt.defineMIME("application/ecmascript","javascript"),rt.defineMIME("application/json",{name:"javascript",json:!0}),rt.defineMIME("application/x-json",{name:"javascript",json:!0}),rt.defineMIME("application/manifest+json",{name:"javascript",json:!0}),rt.defineMIME("application/ld+json",{name:"javascript",jsonld:!0}),rt.defineMIME("text/typescript",{name:"javascript",typescript:!0}),rt.defineMIME("application/typescript",{name:"javascript",typescript:!0})}); -------------------------------------------------------------------------------- /examples/text_editor/ui/js/python.min.js: -------------------------------------------------------------------------------- 1 | !function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(x){"use strict";function k(e){return new RegExp("^(("+e.join(")|(")+"))\\b")}var _=k(["and","or","not","is"]),v=["as","assert","break","class","continue","def","del","elif","else","except","finally","for","from","global","if","import","lambda","pass","raise","return","try","while","with","yield","in"],z=["abs","all","any","bin","bool","bytearray","callable","chr","classmethod","compile","complex","delattr","dict","dir","divmod","enumerate","eval","filter","float","format","frozenset","getattr","globals","hasattr","hash","help","hex","id","input","int","isinstance","issubclass","iter","len","list","locals","map","max","memoryview","min","next","object","oct","open","ord","pow","property","range","repr","reversed","round","set","setattr","slice","sorted","staticmethod","str","sum","super","tuple","type","vars","zip","__import__","NotImplemented","Ellipsis","__debug__"];function w(e){return e.scopes[e.scopes.length-1]}x.registerHelper("hintWords","python",v.concat(z)),x.defineMode("python",function(t,l){for(var s="error",o=l.delimiters||l.singleDelimiters||/^[\(\)\[\]\{\}@,:`=;\.\\]/,a=[l.singleOperators,l.doubleOperators,l.doubleDelimiters,l.tripleDelimiters,l.operators||/^([-+*/%\/&|^]=?|[<>=]+|\/\/=?|\*\*=?|!=|[~!@]|\.\.\.)/],e=0;en;){if("py"!=w(t).type)return 1;t.scopes.pop()}return w(t).offset!=n}function g(e,t){e.sol()&&(t.beginningOfLine=!0,t.dedent=!1);var n,r,i,o=t.tokenize(e,t),a=e.current();if(t.beginningOfLine&&"@"==a)return e.match(c,!1)?"meta":p?"operator":s;if(/\S/.test(a)&&(t.beginningOfLine=!1),"variable"!=o&&"builtin"!=o||"meta"!=t.lastToken||(o="meta"),"pass"!=a&&"return"!=a||(t.dedent=!0),"lambda"==a&&(t.lambda=!0),":"==a&&!t.lambda&&"py"==w(t).type&&e.match(/^\s*(?:#|$)/,!1)&&b(t),1==a.length&&!/string|comment/.test(o)){var l="[({".indexOf(a);if(-1!=l&&(n=e,r=t,i="])}".slice(l,l+1),n=n.match(/^[\s\[\{\(]*(?:#|$)/,!1)?null:n.column()+1,r.scopes.push({offset:r.indent+f,type:i,align:n})),-1!=(l="])}".indexOf(a))){if(w(t).type!=a)return s;t.indent=t.scopes.pop().offset-f}}return t.dedent&&e.eol()&&"py"==w(t).type&&1 codeMirrorInstance.setValue(e.target.result); 57 | reader.readAsText(file); 58 | } 59 | 60 | async function openFile() { 61 | if (supportsFilePicker) { 62 | [fileHandle] = await showOpenFilePicker({ multiple: false }); 63 | fileData = await fileHandle.getFile(); 64 | readFile(fileData); 65 | setFile(fileData); 66 | } else { 67 | let input = document.createElement('input'); 68 | input.type = 'file'; 69 | input.onchange = (e) => { 70 | readFile(e.target.files[0]); 71 | setFile(e.target.files[0]); 72 | }; 73 | input.click(); 74 | input.remove(); 75 | } 76 | } 77 | 78 | async function saveFile() { 79 | const content = codeMirrorInstance.getValue(); 80 | if (supportsFilePicker) { 81 | if (fileHandle) { 82 | // Create a FileSystemWritableFileStream to write to 83 | const writableStream = await fileHandle.createWritable(); 84 | await writableStream.write(content); 85 | // Write to disk 86 | await writableStream.close(); 87 | } else { 88 | fileHandle = await showSaveFilePicker(); 89 | saveFile(); 90 | setFile(await fileHandle.getFile()); 91 | } 92 | } else { 93 | // Download the file if using filePicker with a fileHandle for saving 94 | // is not supported by the browser. E.g., in Firefox. 95 | const blobData = new Blob([content], { type: 'text/${currentFile.ext}' }); 96 | const urlToBlob = window.URL.createObjectURL(blobData); 97 | const a = document.createElement('a'); 98 | a.style.setProperty('display', 'none'); 99 | a.href = urlToBlob; 100 | a.download = document.title; 101 | a.click(); 102 | window.URL.revokeObjectURL(urlToBlob); 103 | a.remove(); 104 | } 105 | saveBtn.disabled = true; 106 | } 107 | 108 | // Navigation Events 109 | // open 110 | document.getElementById('open-btn').onclick = openFile; 111 | // save 112 | saveBtn.onclick = saveFile; 113 | // about 114 | document.getElementById('about-btn').onclick = () => (aboutBox.style.display = 'block'); // show 115 | aboutBox.onclick = () => (aboutBox.style.display = 'none'); // hide 116 | 117 | // Editor Events 118 | // enable save on change 119 | codeMirrorInstance.on('change', () => { 120 | saveBtn.disabled = false; 121 | }); 122 | window.addEventListener('DOMContentLoaded', () => { 123 | codeMirrorInstance.setSize('100%', '99%'); 124 | }); 125 | -------------------------------------------------------------------------------- /examples/text_editor/ui/js/xml.min.js: -------------------------------------------------------------------------------- 1 | !function(t){"object"==typeof exports&&"object"==typeof module?t(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],t):t(CodeMirror)}(function(y){"use strict";var C={autoSelfClosers:{area:!0,base:!0,br:!0,col:!0,command:!0,embed:!0,frame:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0,menuitem:!0},implicitlyClosed:{dd:!0,li:!0,optgroup:!0,option:!0,p:!0,rp:!0,rt:!0,tbody:!0,td:!0,tfoot:!0,th:!0,tr:!0},contextGrabbers:{dd:{dd:!0,dt:!0},dt:{dd:!0,dt:!0},li:{li:!0},option:{option:!0,optgroup:!0},optgroup:{optgroup:!0},p:{address:!0,article:!0,aside:!0,blockquote:!0,dir:!0,div:!0,dl:!0,fieldset:!0,footer:!0,form:!0,h1:!0,h2:!0,h3:!0,h4:!0,h5:!0,h6:!0,header:!0,hgroup:!0,hr:!0,menu:!0,nav:!0,ol:!0,p:!0,pre:!0,section:!0,table:!0,ul:!0},rp:{rp:!0,rt:!0},rt:{rp:!0,rt:!0},tbody:{tbody:!0,tfoot:!0},td:{td:!0,th:!0},tfoot:{tbody:!0},th:{td:!0,th:!0},thead:{tbody:!0,tfoot:!0},tr:{tr:!0}},doNotIndent:{pre:!0},allowUnquoted:!0,allowMissing:!0,caseFold:!0},z={autoSelfClosers:{},implicitlyClosed:{},contextGrabbers:{},doNotIndent:{},allowUnquoted:!1,allowMissing:!1,allowMissingTagName:!1,caseFold:!1};y.defineMode("xml",function(t,e){var n,i,a,l=t.indentUnit,u={},r=e.htmlMode?C:z;for(n in r)u[n]=r[n];for(n in e)u[n]=e[n];function c(e,n){function t(t){return(n.tokenize=t)(e,n)}var r=e.next();return"<"==r?e.eat("!")?e.eat("[")?e.match("CDATA[")?t(o("atom","]]>")):null:e.match("--")?t(o("comment","--\x3e")):e.match("DOCTYPE",!0,!0)?(e.eatWhile(/[\w\._\-]/),t(function r(o){return function(t,e){for(var n;null!=(n=t.next());){if("<"==n)return e.tokenize=r(o+1),e.tokenize(t,e);if(">"==n){if(1!=o)return e.tokenize=r(o-1),e.tokenize(t,e);e.tokenize=c;break}}return"meta"}}(1))):null:e.eat("?")?(e.eatWhile(/[\w\._\-]/),n.tokenize=o("meta","?>"),"meta"):(i=e.eat("/")?"closeTag":"openTag",n.tokenize=d,"tag bracket"):"&"==r?(e.eat("#")?e.eat("x")?e.eatWhile(/[a-fA-F\d]/)&&e.eat(";"):e.eatWhile(/[\d]/)&&e.eat(";"):e.eatWhile(/[\w\.\-:]/)&&e.eat(";"))?"atom":"error":(e.eatWhile(/[^&<]/),null)}function d(t,e){var n,r,o=t.next();return">"==o||"/"==o&&t.eat(">")?(e.tokenize=c,i=">"==o?"endTag":"selfcloseTag","tag bracket"):"="==o?(i="equals",null):"<"==o?(e.tokenize=c,e.state=p,e.tagName=e.tagStart=null,(n=e.tokenize(t,e))?n+" tag error":"tag error"):/[\'\"]/.test(o)?(e.tokenize=(r=o,a.isInAttribute=!0,a),e.stringStartCol=t.column(),e.tokenize(t,e)):(t.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/),"word");function a(t,e){for(;!t.eol();)if(t.next()==r){e.tokenize=d;break}return"string"}}function o(n,r){return function(t,e){for(;!t.eol();){if(t.match(r)){e.tokenize=c;break}t.next()}return n}}function s(t){return t&&t.toLowerCase()}function f(t,e,n){this.prev=t.context,this.tagName=e||"",this.indent=t.indented,this.startOfLine=n,(u.doNotIndent.hasOwnProperty(e)||t.context&&t.context.noIndent)&&(this.noIndent=!0)}function m(t){t.context&&(t.context=t.context.prev)}function g(t,e){for(var n;;){if(!t.context)return;if(n=t.context.tagName,!u.contextGrabbers.hasOwnProperty(s(n))||!u.contextGrabbers[s(n)].hasOwnProperty(s(e)))return;m(t)}}function p(t,e,n){return"openTag"==t?(n.tagStart=e.column(),h):"closeTag"==t?x:p}function h(t,e,n){return"word"==t?(n.tagName=e.current(),a="tag",w):u.allowMissingTagName&&"endTag"==t?(a="tag bracket",w(t,0,n)):(a="error",h)}function x(t,e,n){var r;return"word"==t?(r=e.current(),n.context&&n.context.tagName!=r&&u.implicitlyClosed.hasOwnProperty(s(n.context.tagName))&&m(n),n.context&&n.context.tagName==r||!1===u.matchClosing?(a="tag",b):(a="tag error",k)):u.allowMissingTagName&&"endTag"==t?(a="tag bracket",b(t,0,n)):(a="error",k)}function b(t,e,n){return"endTag"!=t?(a="error",b):(m(n),p)}function k(t,e,n){return a="error",b(t,0,n)}function w(t,e,n){return"word"==t?(a="attribute",T):"endTag"==t||"selfcloseTag"==t?(r=n.tagName,o=n.tagStart,n.tagName=n.tagStart=null,"selfcloseTag"==t||u.autoSelfClosers.hasOwnProperty(s(r))?g(n,r):(g(n,r),n.context=new f(n,r,o==n.indented)),p):(a="error",w);var r,o}function T(t,e,n){return"equals"==t?v:(u.allowMissing||(a="error"),w(t,0,n))}function v(t,e,n){return"string"==t?N:"word"==t&&u.allowUnquoted?(a="string",w):(a="error",w(t,0,n))}function N(t,e,n){return"string"==t?N:w(t,0,n)}return c.isInText=!0,{startState:function(t){var e={tokenize:c,state:p,indented:t||0,tagName:null,tagStart:null,context:null};return null!=t&&(e.baseIndent=t),e},token:function(t,e){if(!e.tagName&&t.sol()&&(e.indented=t.indentation()),t.eatSpace())return null;i=null;var n=e.tokenize(t,e);return(n||i)&&"comment"!=n&&(a=null,e.state=e.state(i||n,t,e),a&&(n="error"==a?n+" error":a)),n},indent:function(t,e,n){var r=t.context;if(t.tokenize.isInAttribute)return t.tagStart==t.indented?t.stringStartCol+1:t.indented+l;if(r&&r.noIndent)return y.Pass;if(t.tokenize!=d&&t.tokenize!=c)return n?n.match(/^(\s*)/)[0].length:0;if(t.tagName)return!1!==u.multilineTagIndentPastTag?t.tagStart+t.tagName.length+2:t.tagStart+l*(u.multilineTagIndentFactor||1);if(u.alignCDATA&&/$/,blockCommentStart:"\x3c!--",blockCommentEnd:"--\x3e",configuration:u.htmlMode?"html":"xml",helperType:u.htmlMode?"html":"xml",skipAttribute:function(t){t.state==v&&(t.state=w)},xmlCurrentTag:function(t){return t.tagName?{name:t.tagName,close:"closeTag"==t.type}:null},xmlCurrentContext:function(t){for(var e=[],n=t.context;n;n=n.prev)e.push(n.tagName);return e.reverse()}}}),y.defineMIME("text/xml","xml"),y.defineMIME("application/xml","xml"),y.mimeModes.hasOwnProperty("text/html")||y.defineMIME("text/html",{name:"xml",htmlMode:!0})}); -------------------------------------------------------------------------------- /examples/text_editor/ui/webfonts/fa-brands-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webui-dev/zig-webui/a58faf0fb206725ee443d1af6f6b1ebc88187e6a/examples/text_editor/ui/webfonts/fa-brands-400.eot -------------------------------------------------------------------------------- /examples/text_editor/ui/webfonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webui-dev/zig-webui/a58faf0fb206725ee443d1af6f6b1ebc88187e6a/examples/text_editor/ui/webfonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /examples/text_editor/ui/webfonts/fa-brands-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webui-dev/zig-webui/a58faf0fb206725ee443d1af6f6b1ebc88187e6a/examples/text_editor/ui/webfonts/fa-brands-400.woff -------------------------------------------------------------------------------- /examples/text_editor/ui/webfonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webui-dev/zig-webui/a58faf0fb206725ee443d1af6f6b1ebc88187e6a/examples/text_editor/ui/webfonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /examples/text_editor/ui/webfonts/fa-regular-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webui-dev/zig-webui/a58faf0fb206725ee443d1af6f6b1ebc88187e6a/examples/text_editor/ui/webfonts/fa-regular-400.eot -------------------------------------------------------------------------------- /examples/text_editor/ui/webfonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webui-dev/zig-webui/a58faf0fb206725ee443d1af6f6b1ebc88187e6a/examples/text_editor/ui/webfonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /examples/text_editor/ui/webfonts/fa-regular-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webui-dev/zig-webui/a58faf0fb206725ee443d1af6f6b1ebc88187e6a/examples/text_editor/ui/webfonts/fa-regular-400.woff -------------------------------------------------------------------------------- /examples/text_editor/ui/webfonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webui-dev/zig-webui/a58faf0fb206725ee443d1af6f6b1ebc88187e6a/examples/text_editor/ui/webfonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /examples/text_editor/ui/webfonts/fa-solid-900.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webui-dev/zig-webui/a58faf0fb206725ee443d1af6f6b1ebc88187e6a/examples/text_editor/ui/webfonts/fa-solid-900.eot -------------------------------------------------------------------------------- /examples/text_editor/ui/webfonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webui-dev/zig-webui/a58faf0fb206725ee443d1af6f6b1ebc88187e6a/examples/text_editor/ui/webfonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /examples/text_editor/ui/webfonts/fa-solid-900.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webui-dev/zig-webui/a58faf0fb206725ee443d1af6f6b1ebc88187e6a/examples/text_editor/ui/webfonts/fa-solid-900.woff -------------------------------------------------------------------------------- /examples/text_editor/ui/webfonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webui-dev/zig-webui/a58faf0fb206725ee443d1af6f6b1ebc88187e6a/examples/text_editor/ui/webfonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /examples/web_app_multi_client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | WebUI - Web App Multi-Client Example 6 | 56 | 57 | 58 |

Web App Multi-Client Example

59 |
60 | Connecting... 61 |
62 |
63 | You are user numer 0 64 |
65 |
66 | Your connection numer is 0 67 |
68 |
69 | There is 0 users connected, and 0 tab opened. 70 |
71 |
72 | Current user input: Reload This Page 73 |
74 |
75 | All users input: 76 |
77 |
78 | Open New Tab 79 |
80 |
81 | 82 |
83 |
84 |
85 | Note:
Copy URL, and open it in a private window, or another web browser to create new users. 86 | 87 | 88 | 89 | 90 | 91 | 155 | 156 | -------------------------------------------------------------------------------- /examples/web_app_multi_client/main.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const webui = @import("webui"); 3 | 4 | // general purpose allocator 5 | var gpa = std.heap.GeneralPurposeAllocator(.{}){}; 6 | // allocator 7 | const allocator = gpa.allocator(); 8 | 9 | var private_input_arr = std.mem.zeroes([256]?[]u8); 10 | var public_input = std.mem.zeroes(?[]u8); 11 | var users_count: usize = 0; 12 | var tab_count: usize = 0; 13 | 14 | fn exit_app(_: *webui.Event) void { 15 | // Close all opened windows 16 | webui.exit(); 17 | } 18 | 19 | fn save(e: *webui.Event) void { 20 | // Get input value 21 | const privateInput = e.getString(); 22 | 23 | // free previous memory 24 | if (private_input_arr[e.client_id]) |val| 25 | allocator.free(val); 26 | 27 | // allocate new memory, to save new private input 28 | private_input_arr[e.client_id] = allocator.dupe(u8, privateInput) catch unreachable; 29 | } 30 | 31 | fn saveAll(e: *webui.Event) void { 32 | // Get input value 33 | const publicInput = e.getString(); 34 | 35 | // free previous memory 36 | if (public_input) |val| 37 | allocator.free(val); 38 | 39 | // allocate new memory to save new public input 40 | public_input = allocator.dupe(u8, publicInput) catch unreachable; 41 | 42 | // general new js 43 | const js = std.fmt.allocPrintZ( 44 | allocator, 45 | "document.getElementById(\"publicInput\").value = \"{s}\";", 46 | .{publicInput}, 47 | ) catch unreachable; 48 | // free js 49 | defer allocator.free(js); 50 | 51 | var win = e.getWindow(); 52 | win.run(js); 53 | } 54 | 55 | fn events(e: *webui.Event) void { 56 | // This function gets called every time 57 | // there is an event 58 | 59 | // Full web browser cookies 60 | // const cookies = e.cookies; 61 | 62 | // Static client (Based on web browser cookies) 63 | const client_id = e.client_id; 64 | 65 | // Dynamic client connection ID (Changes on connect/disconnect events) 66 | const connection_id = e.connection_id; 67 | 68 | if (e.event_type == .EVENT_CONNECTED) { 69 | // New connection 70 | if (users_count < (client_id + 1)) 71 | users_count = client_id + 1; 72 | tab_count += 1; 73 | } else if (e.event_type == .EVENT_DISCONNECTED) { 74 | // Disconnection 75 | if (tab_count > 0) 76 | tab_count -= 1; 77 | } 78 | 79 | // Buffer 80 | 81 | // Update this current user only 82 | 83 | e.runClient("document.getElementById(\"status\").innerText = \"Connected!\";"); 84 | 85 | // userNumber 86 | { 87 | var buffer = std.mem.zeroes([2048]u8); 88 | const js = std.fmt.bufPrintZ( 89 | &buffer, 90 | "document.getElementById(\"userNumber\").innerText = \"{}\";", 91 | .{client_id}, 92 | ) catch unreachable; 93 | e.runClient(js); 94 | } 95 | 96 | // connectionNumber 97 | { 98 | var buffer = std.mem.zeroes([2048]u8); 99 | const js = std.fmt.bufPrintZ( 100 | &buffer, 101 | "document.getElementById(\"connectionNumber\").innerText = \"{}\";", 102 | .{connection_id}, 103 | ) catch unreachable; 104 | e.runClient(js); 105 | } 106 | 107 | // privateInput 108 | { 109 | const val = if (private_input_arr[client_id]) |val| val else ""; 110 | 111 | var buffer = std.mem.zeroes([2048]u8); 112 | const js = std.fmt.bufPrintZ( 113 | &buffer, 114 | "document.getElementById(\"privateInput\").value = \"{s}\";", 115 | .{val}, 116 | ) catch unreachable; 117 | e.runClient(js); 118 | } 119 | 120 | // publicInput 121 | { 122 | const val = if (public_input) |val| val else ""; 123 | var buffer = std.mem.zeroes([2048]u8); 124 | const js = std.fmt.bufPrintZ( 125 | &buffer, 126 | "document.getElementById(\"publicInput\").value = \"{s}\";", 127 | .{val}, 128 | ) catch unreachable; 129 | e.runClient(js); 130 | } 131 | 132 | // Update all connected users 133 | 134 | var win = e.getWindow(); 135 | // userCount 136 | { 137 | var buffer = std.mem.zeroes([2048]u8); 138 | const js = std.fmt.bufPrintZ( 139 | &buffer, 140 | "document.getElementById(\"userCount\").innerText = \"{}\";", 141 | .{users_count}, 142 | ) catch unreachable; 143 | win.run(js); 144 | } 145 | 146 | // tabCount 147 | { 148 | var buffer = std.mem.zeroes([2048]u8); 149 | const js = std.fmt.bufPrintZ( 150 | &buffer, 151 | "document.getElementById(\"tabCount\").innerText = \"{}\";", 152 | .{tab_count}, 153 | ) catch unreachable; 154 | win.run(js); 155 | } 156 | } 157 | 158 | pub fn main() !void { 159 | defer { 160 | const deinit_status = gpa.deinit(); 161 | 162 | if (deinit_status == .leak) @panic("memory leak!"); 163 | } 164 | 165 | // when program exit, we will free all memory allocated! 166 | defer { 167 | for (private_input_arr) |val| { 168 | if (val) |v| 169 | allocator.free(v); 170 | } 171 | if (public_input) |val| 172 | allocator.free(val); 173 | } 174 | 175 | // Allow multi-user connection 176 | webui.setConfig(.multi_client, true); 177 | 178 | // Allow cookies 179 | webui.setConfig(.use_cookies, true); 180 | 181 | // Create new window 182 | var win = webui.newWindow(); 183 | 184 | // Bind HTML with a Zig functions 185 | _ = try win.bind("save", save); 186 | _ = try win.bind("saveAll", saveAll); 187 | _ = try win.bind("exit_app", exit_app); 188 | 189 | // Bind all events 190 | _ = try win.bind("", events); 191 | 192 | // Start server only 193 | const url = try win.startServer("index.html"); 194 | 195 | // Open a new page in the default native web browser 196 | webui.openUrl(@as([*c]const u8, @ptrCast(url.ptr))[0..url.len :0]); 197 | 198 | // Wait until all windows get closed 199 | webui.wait(); 200 | 201 | // Free all memory resources (Optional) 202 | webui.clean(); 203 | } 204 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "flake-compat": { 4 | "flake": false, 5 | "locked": { 6 | "lastModified": 1673956053, 7 | "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", 8 | "owner": "edolstra", 9 | "repo": "flake-compat", 10 | "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", 11 | "type": "github" 12 | }, 13 | "original": { 14 | "owner": "edolstra", 15 | "repo": "flake-compat", 16 | "type": "github" 17 | } 18 | }, 19 | "flake-compat_2": { 20 | "flake": false, 21 | "locked": { 22 | "lastModified": 1673956053, 23 | "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", 24 | "owner": "edolstra", 25 | "repo": "flake-compat", 26 | "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", 27 | "type": "github" 28 | }, 29 | "original": { 30 | "owner": "edolstra", 31 | "repo": "flake-compat", 32 | "type": "github" 33 | } 34 | }, 35 | "flake-utils": { 36 | "locked": { 37 | "lastModified": 1659877975, 38 | "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", 39 | "owner": "numtide", 40 | "repo": "flake-utils", 41 | "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", 42 | "type": "github" 43 | }, 44 | "original": { 45 | "owner": "numtide", 46 | "repo": "flake-utils", 47 | "type": "github" 48 | } 49 | }, 50 | "flake-utils_2": { 51 | "inputs": { 52 | "systems": "systems" 53 | }, 54 | "locked": { 55 | "lastModified": 1710146030, 56 | "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", 57 | "owner": "numtide", 58 | "repo": "flake-utils", 59 | "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", 60 | "type": "github" 61 | }, 62 | "original": { 63 | "owner": "numtide", 64 | "repo": "flake-utils", 65 | "type": "github" 66 | } 67 | }, 68 | "flake-utils_3": { 69 | "locked": { 70 | "lastModified": 1659877975, 71 | "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", 72 | "owner": "numtide", 73 | "repo": "flake-utils", 74 | "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", 75 | "type": "github" 76 | }, 77 | "original": { 78 | "owner": "numtide", 79 | "repo": "flake-utils", 80 | "type": "github" 81 | } 82 | }, 83 | "gitignore": { 84 | "inputs": { 85 | "nixpkgs": [ 86 | "zls-overlay", 87 | "nixpkgs" 88 | ] 89 | }, 90 | "locked": { 91 | "lastModified": 1709087332, 92 | "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", 93 | "owner": "hercules-ci", 94 | "repo": "gitignore.nix", 95 | "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", 96 | "type": "github" 97 | }, 98 | "original": { 99 | "owner": "hercules-ci", 100 | "repo": "gitignore.nix", 101 | "type": "github" 102 | } 103 | }, 104 | "langref": { 105 | "flake": false, 106 | "locked": { 107 | "narHash": "sha256-Kz+m9yeJgAsUfNwGG6ZDqZ3ElLZMeQmVYzgg0EEUzV4=", 108 | "type": "file", 109 | "url": "https://raw.githubusercontent.com/ziglang/zig/a685ab1499d6560c523f0dbce2890dc140671e43/doc/langref.html.in" 110 | }, 111 | "original": { 112 | "type": "file", 113 | "url": "https://raw.githubusercontent.com/ziglang/zig/a685ab1499d6560c523f0dbce2890dc140671e43/doc/langref.html.in" 114 | } 115 | }, 116 | "nixpkgs": { 117 | "locked": { 118 | "lastModified": 1715266358, 119 | "narHash": "sha256-doPgfj+7FFe9rfzWo1siAV2mVCasW+Bh8I1cToAXEE4=", 120 | "owner": "nixos", 121 | "repo": "nixpkgs", 122 | "rev": "f1010e0469db743d14519a1efd37e23f8513d714", 123 | "type": "github" 124 | }, 125 | "original": { 126 | "owner": "nixos", 127 | "ref": "nixos-unstable", 128 | "repo": "nixpkgs", 129 | "type": "github" 130 | } 131 | }, 132 | "nixpkgs_2": { 133 | "locked": { 134 | "lastModified": 1702350026, 135 | "narHash": "sha256-A+GNZFZdfl4JdDphYKBJ5Ef1HOiFsP18vQe9mqjmUis=", 136 | "owner": "NixOS", 137 | "repo": "nixpkgs", 138 | "rev": "9463103069725474698139ab10f17a9d125da859", 139 | "type": "github" 140 | }, 141 | "original": { 142 | "owner": "NixOS", 143 | "ref": "nixos-23.05", 144 | "repo": "nixpkgs", 145 | "type": "github" 146 | } 147 | }, 148 | "nixpkgs_3": { 149 | "locked": { 150 | "lastModified": 1714971268, 151 | "narHash": "sha256-IKwMSwHj9+ec660l+I4tki/1NRoeGpyA2GdtdYpAgEw=", 152 | "owner": "NixOS", 153 | "repo": "nixpkgs", 154 | "rev": "27c13997bf450a01219899f5a83bd6ffbfc70d3c", 155 | "type": "github" 156 | }, 157 | "original": { 158 | "owner": "NixOS", 159 | "ref": "nixos-23.11", 160 | "repo": "nixpkgs", 161 | "type": "github" 162 | } 163 | }, 164 | "root": { 165 | "inputs": { 166 | "nixpkgs": "nixpkgs", 167 | "zig-overlay": "zig-overlay", 168 | "zls-overlay": "zls-overlay" 169 | } 170 | }, 171 | "systems": { 172 | "locked": { 173 | "lastModified": 1681028828, 174 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 175 | "owner": "nix-systems", 176 | "repo": "default", 177 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 178 | "type": "github" 179 | }, 180 | "original": { 181 | "owner": "nix-systems", 182 | "repo": "default", 183 | "type": "github" 184 | } 185 | }, 186 | "zig-overlay": { 187 | "inputs": { 188 | "flake-compat": "flake-compat", 189 | "flake-utils": "flake-utils", 190 | "nixpkgs": "nixpkgs_2" 191 | }, 192 | "locked": { 193 | "lastModified": 1715170163, 194 | "narHash": "sha256-EuRzY3HI9sMMqPX7Yb7xkZaBoznP0mtS2O/Kk/r6fYk=", 195 | "owner": "mitchellh", 196 | "repo": "zig-overlay", 197 | "rev": "9c0a853edcab5d60d28784c10b13392d7fabb9d7", 198 | "type": "github" 199 | }, 200 | "original": { 201 | "owner": "mitchellh", 202 | "repo": "zig-overlay", 203 | "type": "github" 204 | } 205 | }, 206 | "zig-overlay_2": { 207 | "inputs": { 208 | "flake-compat": "flake-compat_2", 209 | "flake-utils": "flake-utils_3", 210 | "nixpkgs": [ 211 | "zls-overlay", 212 | "nixpkgs" 213 | ] 214 | }, 215 | "locked": { 216 | "lastModified": 1715041400, 217 | "narHash": "sha256-yI67g+yU2J/tjytr9cTk51feKjLc+f9+BKE1KjlMNLQ=", 218 | "owner": "mitchellh", 219 | "repo": "zig-overlay", 220 | "rev": "48bcb35d1d59509010af9a3da06af8750ab9593b", 221 | "type": "github" 222 | }, 223 | "original": { 224 | "owner": "mitchellh", 225 | "repo": "zig-overlay", 226 | "type": "github" 227 | } 228 | }, 229 | "zls-overlay": { 230 | "inputs": { 231 | "flake-utils": "flake-utils_2", 232 | "gitignore": "gitignore", 233 | "langref": "langref", 234 | "nixpkgs": "nixpkgs_3", 235 | "zig-overlay": "zig-overlay_2" 236 | }, 237 | "locked": { 238 | "lastModified": 1715376937, 239 | "narHash": "sha256-fXZmddq7ZrEaX0rT4n+46f+qpwMbOdhoY+fCRj70xts=", 240 | "owner": "zigtools", 241 | "repo": "zls", 242 | "rev": "bb19beeb38a8c3df9a2408b8e15664415b8347ef", 243 | "type": "github" 244 | }, 245 | "original": { 246 | "owner": "zigtools", 247 | "repo": "zls", 248 | "type": "github" 249 | } 250 | } 251 | }, 252 | "root": "root", 253 | "version": 7 254 | } 255 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "For lua environment"; 3 | 4 | inputs = { 5 | nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; 6 | zig-overlay.url = "github:mitchellh/zig-overlay"; 7 | zls-overlay.url = "github:zigtools/zls"; 8 | }; 9 | 10 | outputs = { self, nixpkgs, ... }@ inputs: 11 | let 12 | systems = [ 13 | # "aarch64-linux" 14 | # "i686-linux" 15 | # "aarch64-darwin" 16 | # "x86_64-darwin" 17 | "x86_64-linux" 18 | ]; 19 | # This is a function that generates an attribute by calling a function you 20 | # pass to it, with each system as an argument 21 | forAllSystems = nixpkgs.lib.genAttrs systems; 22 | in 23 | { 24 | # This is for using nix direnv and flake develop environment 25 | devShells = forAllSystems (system: 26 | let 27 | pkgs = import nixpkgs { 28 | inherit system; 29 | overlays = [ 30 | inputs.zig-overlay.overlays.default 31 | (final: prev: { 32 | zlspkgs = inputs.zls-overlay.packages.${system}.default; 33 | }) 34 | ]; 35 | }; 36 | in 37 | { 38 | default = 39 | pkgs.mkShell { 40 | packages = with pkgs; [ 41 | zigpkgs.default 42 | zls 43 | nodePackages.live-server 44 | ]; 45 | }; 46 | 47 | nightly = 48 | pkgs.mkShell { 49 | packages = with pkgs;[ 50 | zigpkgs.master 51 | zlspkgs 52 | nodePackages.live-server 53 | ]; 54 | }; 55 | }); 56 | }; 57 | } 58 | --------------------------------------------------------------------------------