├── .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 | 
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 | 
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 | 
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 | 
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 | Manual Count
53 |
54 |
55 | Auto Count (Every 10ms)
56 |
57 |
58 | Exit
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 |
48 | Call my_function_string()
49 |
50 |
51 | Call my_function_integer()
52 |
53 |
54 |
55 | Call my_function_boolean()
56 |
57 |
58 |
61 | Call my_function_raw_binary()
62 |
63 |
64 | Call a C function that returns a response
65 | Call my_function_with_response()
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 |
Second Page
22 |
Third Page
23 |
24 |
25 |
26 | Fourth page (JS->Zig->JS)
27 |
28 |
29 |
30 |
31 |
32 |
33 |
This is the First (Home) Page
34 |
35 |
36 |
37 | Example: Web-Server that finds available free port (C)
38 |
39 | Similar to the Custom Web-Server example, this HTML page is handled by a custom Web-Server other than WebUI.
40 | This window is connected to the back-end because we used:
http://localhost:[WEBUI_PORT]/webui.js
41 | An available free port ([WEBUI_PORT]) was obtained by calling webui.getFreePort();
42 |
43 |
44 |
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 |
16 | Call my_backend_func()
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 |
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 | Exit
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 | Deno_test.ts (Local file)
70 |
71 |
72 | Bun_test.ts (Local file)
73 |
74 |
75 | Nodejs_test.ts (Local file)
76 |
77 |
78 |
79 | Switch to The Second Page Programmatically (Local file)
80 |
81 |
82 | Open The Second Window (Local file)
83 |
84 |
85 |
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 | Call Exit()
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 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
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: Save Reload This Page
73 |
74 |
75 | All users input: Update All Users
76 |
77 |
78 | Open New Tab
79 |
80 |
81 | Exit
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 |
--------------------------------------------------------------------------------