diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000000..9b1921a75c --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,38 @@ +name: Tests + +on: + push: + branches: + - dev + - rc + - master + pull_request: + workflow_dispatch: + +permissions: + contents: read + +jobs: + test: + name: Configuration and script checks + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Install test dependencies + run: | + sudo apt-get update + sudo apt-get install -y --no-install-recommends lua5.4 shellcheck + sudo ln -sf /usr/bin/lua5.4 /usr/local/bin/lua + sudo ln -sf /usr/bin/luac5.4 /usr/local/bin/luac + + - name: Report tool versions + run: | + lua -v + shellcheck --version + python3 --version + + - name: Run the test suite + run: sh tests/run.sh diff --git a/.gitignore b/.gitignore index daaecdeaa7..47904e2c48 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,6 @@ Scripts/pkg_user.lst Configs/.config/uwsm/* ./.* build + +# Local agent worktrees, never part of the tree +.claude/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b71725d642..52a9fea759 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,3 +20,8 @@ repos: name: markdownlint-strict args: [--config, .markdownlint-strict.yaml] stages: [manual] + + - repo: https://github.com/Calinou/pre-commit-luacheck + rev: v1.0.0 + hooks: + - id: luacheck diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b0a6c5203..416e049bd2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,42 @@ All notable changes to 'HyDE' will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to _Modified_ [CalVer](https://calver.org/). See [Versioning](https://github.com/HyDE-Project/HyDE/blob/master/RELEASE_POLICY.md#versioning-yymq) For more info --> -## v26.7.28 | End of April Release +## Unreleased + +### Added +- Docs: `MIGRATION-LUA.md`, a transition guide for upgrading from the hyprlang configuration — what moved where, the silent failures and their causes, and the files the upgrade leaves behind + +### Removed +- Hyprland: dropped the legacy hyprlang dot, the files it deployed no longer exist + +### Fixed +- Hyprland: a session started without `XDG_CONFIG_HOME`, such as one launched from a TTY, no longer dies with a Lua error before the first window; the unset variable is treated as unset instead of being pasted into a path +- Hyprland: a home directory containing an apostrophe no longer makes the session load its libraries from the system directory instead of the user's own, and an empty `XDG_RUNTIME_DIR` reads as unset rather than resolving against the working directory +- Waybar: the theme module and the HyDE menu call `theme.switch` again; `themeswitch` was removed and the calls failed outright +- Dolphin: the "Set As Wallpaper" service menu switches the theme again +- Fish: `HYPRLAND_CONFIG` points at the deployed `hypr/hyde.lua` instead of a config the Lua release deleted, so a session started outside uwsm no longer comes up without a config +- Hyprland: the config editor offers the user's `hypr/hyprland.lua` instead of four files nothing reads, which it used to create empty on save +- System monitor: a console monitor no longer launches with no terminal attached, and `[sysmonitor] terminal` is a real setting +- Docs: the keybinding reference describes the Lua configuration instead of the removed `userprefs.conf`, documents binds that were missing from it, corrects four descriptions that no longer matched the code, and explains why an override needs the original bind's flags +- Docs: the shipped `hypr/hyprland.lua` stub shows a working bind instead of pointing at a wiki that does not exist +- Docs: the keybinding links in the German, Arabic, French, Dutch and Turkish readmes resolve again +- Core: every migration that has not been applied yet now runs in version order and is recorded, instead of only the newest one running and retiring the rest unseen +- Core: app launchers no longer show a false error when an unrelated `DEBUG` variable contains a non-boolean value such as `release` +- Desktop: the generated battery notification startup command now launches `batterynotify.lua` instead of the removed shell implementation +- Hyprland: Lua keybinds again match the documented shortcuts for window management, screenshots, wallpapers, Waybar, selectors, workspaces and the scratchpad +- Screenshot: area capture now uses the fixed upstream Grimblast selector instead of prompting for the region twice +- Screenshot: Satty defaults to the compatible GTK GL renderer when no explicit `GSK_RENDERER` is configured +- Screenshot: the "print all monitors" keybind now invokes a full-output capture instead of capturing only the focused monitor +- Waybar `hyprland/workspaces` module adapted to use lua dispatchers +- Hyprland: `Super + Ctrl + arrows` no longer changes the group and the workspace at the same time. + Group navigation uses `Super + Ctrl + H/L` +- Hyprland: the right Control key no longer hides Waybar on its own. Hiding moved to `Super + Ctrl + B` +- Hyprland: workspaces 11-20 on the numpad respond again +- OCR: the language list in the result notification is no longer split across arguments +- Wallpaper: the duplicate check in the kon backend compares against the whole hash list again +- Repo: dropped two stray gitlinks that made `git submodule` fail on a fresh clone + +## v26.7.4 | 4th Week of July 2026 Release **Alright** Looks like hyprland 0.56.1 warns user to use lua so here you go! @@ -36,7 +71,7 @@ Life is tight as of the moment. Any help will do. 💓 mangle with QT. But KDE apps uses ~/.config/kdeglobals which might break KDE apps for multi DE. (No fix for now) -## Fixed +### Fixed - Fix cantarell font - Some minor bugs diff --git a/Configs/.config/fish/conf.d/hyde.fish b/Configs/.config/fish/conf.d/hyde.fish index 61d6869832..7bb2c98e14 100644 --- a/Configs/.config/fish/conf.d/hyde.fish +++ b/Configs/.config/fish/conf.d/hyde.fish @@ -74,7 +74,12 @@ set -gx PARALLEL_HOME "$XDG_CONFIG_HOME/parallel" end if test -z "$HYPRLAND_CONFIG" -set -gx HYPRLAND_CONFIG "$XDG_DATA_HOME/hypr/hyprland.conf" +for candidate in "$XDG_DATA_HOME/hypr/hyde.lua" /usr/local/share/hypr/hyde.lua /usr/share/hypr/hyde.lua +if test -r "$candidate" +set -gx HYPRLAND_CONFIG "$candidate" +break +end +end end fish_add_path $HOME/.local/bin:$PATH diff --git a/Configs/.config/hypr/hyprland.lua b/Configs/.config/hypr/hyprland.lua index 92cdd8066f..d110b85860 100644 --- a/Configs/.config/hypr/hyprland.lua +++ b/Configs/.config/hypr/hyprland.lua @@ -1,5 +1,28 @@ --- User Configuration goeas here. --- Adding keybinding are simple, refer to the wiki and add it here! --- Duplicated keybinding will always respect the last last added, therefore please override keybindings as you wish. ---- use "require()" to load other lua files, for example: --- require("keybindings") --- this will load "keybindings.lua" +-- Your Hyprland configuration. HyDE never overwrites this file. +-- +-- It loads after HyDE's own binds, so settings here take precedence. Replacing +-- a bind needs more than that: see below. HyDE's defaults live in +-- ~/.local/share/hypr/lua/ and are overwritten on every update, so edits there +-- do not survive. +-- +-- Adding a keybind: +-- +-- hl.bind("SUPER + SPACE", hl.dsp.exec_cmd(hyde.sh.gamelauncher()), { +-- description = "[Utilities] game launcher", +-- }) +-- +-- Replacing one of HyDE's: bind the same combination again and yours takes +-- over, but copy its flags across as well. A bind counts as the same one only +-- when its flags match, and `description` is not a flag — miss one and both +-- binds stay live on that combination. Copy the whole options table from +-- ~/.local/share/hypr/lua/key_binds.lua and change only what you need: +-- +-- hl.bind("F9", hl.dsp.exec_cmd(hyde.sh.volumecontrol("-o", "m")), { +-- locked = true, +-- description = "[Hardware Controls|Audio] un/mute output", +-- }) +-- +-- Press SUPER + / to see what is actually loaded, your own binds included. +-- The full reference is KEYBINDINGS.md in the HyDE repository. +-- +-- Other Lua files next to this one can be pulled in with require("name"). diff --git a/Configs/.config/uwsm/env-hyprland.d/00-hyde.sh b/Configs/.config/uwsm/env-hyprland.d/00-hyde.sh index fe4c9cec18..f008a97fa7 100644 --- a/Configs/.config/uwsm/env-hyprland.d/00-hyde.sh +++ b/Configs/.config/uwsm/env-hyprland.d/00-hyde.sh @@ -25,7 +25,7 @@ if [ -z "$HYDE_ACTIVATED" ]; then unset _hyde_activate fi -HYPRLAND_CONFIG="${HYPRLAND_CONFIG:-${XDG_DATA_HOME:-$HOME/.local/share}/hypr/hyprland.lua}" +HYPRLAND_CONFIG="${HYPRLAND_CONFIG:-${XDG_DATA_HOME:-$HOME/.local/share}/hypr/hyde.lua}" HYPRLAND_NO_SD_NOTIFY=1 # If systemd, disables the sd_notify calls. HYPRLAND_NO_SD_VARS=1 # Disables management of variables in systemd and dbus activation environments. diff --git a/Configs/.config/uwsm/env.d/01-gpu.sh b/Configs/.config/uwsm/env.d/01-gpu.sh index 458e9d6df4..04e7d8dab4 100644 --- a/Configs/.config/uwsm/env.d/01-gpu.sh +++ b/Configs/.config/uwsm/env.d/01-gpu.sh @@ -1,3 +1,5 @@ +#!/usr/bin/env sh + # 00-gpu.sh - GPU detection # This env script will detect the presence of various GPUs on the system # and set environment variables accordingly. diff --git a/Configs/.config/zsh/ohmyzsh b/Configs/.config/zsh/ohmyzsh deleted file mode 160000 index 9e23925b85..0000000000 --- a/Configs/.config/zsh/ohmyzsh +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9e23925b8581d22033f07f1983587412d3761494 diff --git a/Configs/.local/bin/hyde-shell b/Configs/.local/bin/hyde-shell index db84a2c080..5c7cb32530 100755 --- a/Configs/.local/bin/hyde-shell +++ b/Configs/.local/bin/hyde-shell @@ -294,10 +294,10 @@ run_command() { [[ -d "$dir" ]] && SCRIPT_DIRS+=("$dir") done + # Lua is resolved before shell, so a script left behind by an older release + # cannot shadow the implementation that replaced it. for dir in "${SCRIPT_DIRS[@]}"; do - if [[ -f "$dir/${1}.sh" ]]; then - exec bash "$dir/${1}.sh" "${@:2}" - elif [[ -f "$dir/${1}.lua" ]]; then + if [[ -f "$dir/${1}.lua" ]]; then l_env="${XDG_STATE_HOME:-$HOME/.local/state}/hyde/lua_env" if [[ ! -d "$l_env" ]]; then print_log -warn "Lua environment not found!" " Please run 'hyde-shell luainit' to set up the environment." @@ -315,6 +315,8 @@ run_command() { export LUA_PATH="$l_env/share/lua/$lua_ver/?.lua;$l_env/share/lua/$lua_ver/?/init.lua;$LUA_PATH" export LUA_CPATH="$l_env/lib/lua/$lua_ver/?.so;$LUA_CPATH" exec lua "$dir/${1}.lua" "${@:2}" + elif [[ -f "$dir/${1}.sh" ]]; then + exec bash "$dir/${1}.sh" "${@:2}" elif [[ -f "$dir/${1}.py" ]]; then exec "${XDG_STATE_HOME:-$HOME/.local/state}/hyde/python_env/bin/python" "$dir/${1}.py" "${@:2}" elif [[ -f "$dir/${1}" && -x "$dir/${1}" ]]; then diff --git a/Configs/.local/lib/hyde/app.sh b/Configs/.local/lib/hyde/app.sh index f26ebf956a..3f3c1d5bf2 100755 --- a/Configs/.local/lib/hyde/app.sh +++ b/Configs/.local/lib/hyde/app.sh @@ -5,6 +5,14 @@ # @cmd: service # @cmd.desc: Run a script as a systemd service +# app2unit and xdg-terminal-exec fall back to the generic DEBUG variable, +# which may contain non-boolean build modes such as "release". +# Give both helpers an explicit, scoped default while preserving any +# user-provided values on both execution paths. +APP2UNIT_DEBUG=${APP2UNIT_DEBUG:-0} +XTE_DEBUG=${XTE_DEBUG:-0} +export APP2UNIT_DEBUG XTE_DEBUG + if [ -d "/run/systemd/system" ]; then exec app2unit "$@" fi diff --git a/Configs/.local/lib/hyde/hyde-launch.sh b/Configs/.local/lib/hyde/hyde-launch.sh index c71ccaf899..821181baae 100755 --- a/Configs/.local/lib/hyde/hyde-launch.sh +++ b/Configs/.local/lib/hyde/hyde-launch.sh @@ -3,4 +3,4 @@ notify-send -a "Deprecation Notice" "hyde-launch.sh is deprecated. Please use hyde-shell open instead." -i dialog-information -"${LIB_DIR}/hyde/open.sh" "$@" +hyde-shell open "$@" diff --git a/Configs/.local/lib/hyde/keybinds_hint.sh b/Configs/.local/lib/hyde/keybinds_hint.sh index 18c829579c..23d41cc70c 100755 --- a/Configs/.local/lib/hyde/keybinds_hint.sh +++ b/Configs/.local/lib/hyde/keybinds_hint.sh @@ -1,10 +1,6 @@ #!/usr/bin/env bash pkill -x rofi && exit [[ $HYDE_SHELL_INIT -ne 1 ]] && eval "$(hyde-shell init)" -confDir="${XDG_CONFIG_HOME:-$HOME/.config}" -keyconfDir="$confDir/hypr" -kb_hint_conf=("$keyconfDir/hyprland.conf" "$keyconfDir/keybindings.conf" "$keyconfDir/userprefs.conf") -kb_hint_conf+=("${ROFI_KEYBIND_HINT_CONFIG[@]}") kb_cache="$XDG_RUNTIME_DIR/hyde/keybinds_hint.rofi" if [[ $1 == "--reload" ]]; then diff --git a/Configs/.local/lib/hyde/luautils/xdg.lua b/Configs/.local/lib/hyde/luautils/xdg.lua index 49eb9d85b6..65e9e5b727 100644 --- a/Configs/.local/lib/hyde/luautils/xdg.lua +++ b/Configs/.local/lib/hyde/luautils/xdg.lua @@ -1,12 +1,21 @@ --- @module luautils.xdg -- XDG Base Directory Specification https://specifications.freedesktop.org/basedir-spec/latest/ local HOME = os.getenv("HOME") +--- Per the spec, a variable that is set but empty is treated as unset. local function env(var, fallback) - return os.getenv(var) or (HOME and HOME .. fallback) + local value = os.getenv(var) + if value == nil or value == "" then + return HOME and HOME .. fallback + end + return value end local function dirs(var, default, home) local t = {} - for e in (os.getenv(var) or default):gmatch("([^:]+)") do + local value = os.getenv(var) + if value == nil or value == "" then + value = default + end + for e in value:gmatch("([^:]+)") do t[#t + 1] = e end if home then diff --git a/Configs/.local/lib/hyde/pm.sh b/Configs/.local/lib/hyde/pm.sh index 3778618008..099143d8a0 100755 --- a/Configs/.local/lib/hyde/pm.sh +++ b/Configs/.local/lib/hyde/pm.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env sh +#!/usr/bin/env bash set -eu export LC_ALL=C usage() { diff --git a/Configs/.local/lib/hyde/pyproject.toml b/Configs/.local/lib/hyde/pyproject.toml index 5e9ee08de1..229d2aa944 100644 --- a/Configs/.local/lib/hyde/pyproject.toml +++ b/Configs/.local/lib/hyde/pyproject.toml @@ -5,14 +5,14 @@ requires-python = ">=3.11" dependencies = [ "loguru==0.7.3", "pulsectl==24.12.0", - "requests==2.33.0", + "requests==2.34.2", "inotify_simple", "hererocks>=0.25.1", "websockets>=16.0", "xdg-prefs", "uv>=0.1.0", "deez-dots", - "pyprland==3.3.1", + "pyprland==3.4.3", ] [project.optional-dependencies] diff --git a/Configs/.local/lib/hyde/pyutils/lua_env.json b/Configs/.local/lib/hyde/pyutils/lua_env.json index 86a1ecd4bf..1f5d042aea 100644 --- a/Configs/.local/lib/hyde/pyutils/lua_env.json +++ b/Configs/.local/lib/hyde/pyutils/lua_env.json @@ -2,7 +2,7 @@ "bootstrap_install": [ {"name": "luasec", "version": "1.3.2-1"}, {"name": "argparse", "version": "0.7.2-1"}, - {"name": "dkjson", "version": "2.9-1"}, + {"name": "dkjson", "version": "2.11-1"}, {"name": "luasocket", "version": "3.1.0-1"}, {"name": "luafilesystem", "version": "1.9.0-1"}, "https://raw.githubusercontent.com/lgi-devs/lgi/master/lgi-scm-1.rockspec" diff --git a/Configs/.local/lib/hyde/screenshot.sh b/Configs/.local/lib/hyde/screenshot.sh index ce6c01533d..9148f2d437 100755 --- a/Configs/.local/lib/hyde/screenshot.sh +++ b/Configs/.local/lib/hyde/screenshot.sh @@ -90,6 +90,14 @@ fi [[ -n ${SCREENSHOT_ANNOTATION_ARGS[*]} ]] && annotation_args+=("${SCREENSHOT_ANNOTATION_ARGS[@]}") +run_annotation_tool() { + if [[ $annotation_tool == "satty" ]]; then + GSK_RENDERER="${GSK_RENDERER:-gl}" "$annotation_tool" "${annotation_args[@]}" + else + "$annotation_tool" "${annotation_args[@]}" + fi +} + take_screenshot() { local mode=$1 shift @@ -102,7 +110,7 @@ take_screenshot() { print_log -g "Executing screenshot command: ${command[*]}" if eval "${command[*]}"; then [[ ${SCREENSHOT_ANNOTATION_ENABLED} == false ]] && return 0 - if ! "$annotation_tool" "${annotation_args[@]}"; then + if ! run_annotation_tool; then send_notifs -r 9 -a "HyDE Alert" "Screenshot Error" "Failed to open annotation tool" return 1 fi diff --git a/Configs/.local/lib/hyde/shaders.lua b/Configs/.local/lib/hyde/shaders.lua index ccd90cc1fc..93c8b3bf24 100644 --- a/Configs/.local/lib/hyde/shaders.lua +++ b/Configs/.local/lib/hyde/shaders.lua @@ -35,6 +35,32 @@ local function find_include(base) return nil end +-- Falls back to the XDG defaults when a variable is not exported, so a shader +-- referencing "$XDG_CACHE_HOME" still resolves outside of a HyDE session. +local ENV_FALLBACK = { + XDG_DATA_HOME = xdg.data, + XDG_CONFIG_HOME = xdg.config, + XDG_CACHE_HOME = xdg.cache, + XDG_STATE_HOME = xdg.state, + XDG_RUNTIME_DIR = xdg.runtime, + HOME = os.getenv("HOME") +} + +-- Expands "$VAR" and "${VAR}" occurrences in a path. A variable that is set but +-- empty counts as unset, so the fallback still applies. +local function expand_env(str) + local function lookup(name) + local value = os.getenv(name) + if value == nil or value == "" then + value = ENV_FALLBACK[name] + end + return value or "" + end + str = str:gsub("%${([%w_]+)}", lookup) + str = str:gsub("%$([%w_]+)", lookup) + return str +end + local function parse_source_include(path) local source_include local shader_dir = path:match("^(.*)/") or "." @@ -45,6 +71,7 @@ local function parse_source_include(path) for line in f:lines() do local source = line:match("^%s*//%s*!source%s*=%s*(.-)%s*$") if source and source ~= "" then + source = expand_env(source) if source:sub(1, 1) ~= "/" then source = shader_dir .. "/" .. source end @@ -89,7 +116,10 @@ local function compile_shader(item) local source_include = parse_source_include(src) local files = {} - if source_include and lfs.attributes(source_include, "mode") == "file" then + if source_include then + if lfs.attributes(source_include, "mode") ~= "file" then + return nil, "source include not found: " .. source_include + end files[#files + 1] = source_include end if inc_path then diff --git a/Configs/.local/lib/hyde/shell/activate b/Configs/.local/lib/hyde/shell/activate index 08b6f3c547..0013cb4431 100644 --- a/Configs/.local/lib/hyde/shell/activate +++ b/Configs/.local/lib/hyde/shell/activate @@ -7,6 +7,24 @@ HYDE_ACTIVATED=1 HYDE_MODE="" HYPRLAND_CONFIG="" +# A per-user runtime directory. Falling back to a shared directory would put +# sockets from every session into one namespace, so the fallback is private and +# only readable by its owner. +hyde_runtime_dir() { + _uid=$(id -u 2>/dev/null) || _uid='' + + if [ -n "$_uid" ] && [ -d "/run/user/$_uid" ] && [ -w "/run/user/$_uid" ]; then + printf '%s\n' "/run/user/$_uid" + unset _uid + return 0 + fi + + _dir="${TMPDIR:-/tmp}/hyde-${_uid:-$$}" + mkdir -p "$_dir" 2>/dev/null && chmod 700 "$_dir" 2>/dev/null + printf '%s\n' "$_dir" + unset _uid _dir +} + setup_xdg() { : "${XDG_CONFIG_HOME:=$HOME/.config}" : "${XDG_CACHE_HOME:=$HOME/.cache}" @@ -14,7 +32,7 @@ setup_xdg() { : "${XDG_STATE_HOME:=$HOME/.local/state}" # fallback only - : "${XDG_RUNTIME_DIR:=/tmp}" + [ -n "${XDG_RUNTIME_DIR:-}" ] || XDG_RUNTIME_DIR=$(hyde_runtime_dir) export XDG_CONFIG_HOME XDG_CACHE_HOME XDG_DATA_HOME XDG_STATE_HOME XDG_RUNTIME_DIR } @@ -69,18 +87,49 @@ hyprland_has_lua() { return 1 } +# Mirrors the resolution order in pyutils/lua_env.py, so a runtime that is good +# enough to provision the environment is not rejected here. +hyde_find_bin() { + for _candidate in "$@"; do + [ -n "$_candidate" ] || continue + if command -v "$_candidate" >/dev/null 2>&1; then + printf '%s\n' "$_candidate" + unset _candidate + return 0 + fi + done + + unset _candidate + return 1 +} + +hyde_find_lua() { + hyde_find_bin "${LUA:-}" lua lua5.5 lua5.4 lua5.3 +} + +hyde_find_luarocks() { + hyde_find_bin "${LUAROCKS:-}" luarocks luarocks-5.5 luarocks-5.4 luarocks-5.3 +} + check_lua_runtime() { - hyde_has lua || return 1 - hyde_has luarocks || return 1 + _missing='' + hyde_find_lua >/dev/null || _missing='lua' + hyde_find_luarocks >/dev/null || _missing="${_missing:+$_missing }luarocks" + + [ -z "$_missing" ] || { + printf 'Lua runtime incomplete, missing: %s\n' "$_missing" >&2 + unset _missing + return 1 + } + + unset _missing + return 0 } setup_lua_mode() { HYPRLAND_CONFIG=$(find_hyde_lua) - check_lua_runtime || { - printf 'Lua runtime incomplete\n' >&2 - return 1 - } + check_lua_runtime || return 1 hyprland_has_lua || { printf 'Hyprland lacks Lua support\n' >&2 diff --git a/Configs/.local/lib/hyde/shell/activate.fish b/Configs/.local/lib/hyde/shell/activate.fish index 52821d1460..e6d39de5ee 100644 --- a/Configs/.local/lib/hyde/shell/activate.fish +++ b/Configs/.local/lib/hyde/shell/activate.fish @@ -9,12 +9,30 @@ set -x HYDE_ACTIVATED 1 set -x HYDE_MODE "" set -x HYPRLAND_CONFIG "" +# A per-user runtime directory. Falling back to a shared directory would put +# sockets from every session into one namespace, so the fallback is private and +# only readable by its owner. +function hyde_runtime_dir + set -l uid (id -u 2>/dev/null) + if test -n "$uid" -a -d "/run/user/$uid" -a -w "/run/user/$uid" + echo "/run/user/$uid" + return 0 + end + set -l tmp $TMPDIR + test -n "$tmp"; or set tmp /tmp + set -l dir "$tmp/hyde-$uid" + mkdir -p $dir 2>/dev/null; and chmod 700 $dir 2>/dev/null + echo $dir +end + +# Assignment is unconditional so a value that already exists in a non-exported +# scope still reaches child processes. function setup_xdg - set -q XDG_CONFIG_HOME; or set -x XDG_CONFIG_HOME "$HOME/.config" - set -q XDG_CACHE_HOME; or set -x XDG_CACHE_HOME "$HOME/.cache" - set -q XDG_DATA_HOME; or set -x XDG_DATA_HOME "$HOME/.local/share" - set -q XDG_STATE_HOME; or set -x XDG_STATE_HOME "$HOME/.local/state" - set -q XDG_RUNTIME_DIR; or set -x XDG_RUNTIME_DIR "/tmp" + set -gx XDG_CONFIG_HOME (test -n "$XDG_CONFIG_HOME"; and echo $XDG_CONFIG_HOME; or echo "$HOME/.config") + set -gx XDG_CACHE_HOME (test -n "$XDG_CACHE_HOME"; and echo $XDG_CACHE_HOME; or echo "$HOME/.cache") + set -gx XDG_DATA_HOME (test -n "$XDG_DATA_HOME"; and echo $XDG_DATA_HOME; or echo "$HOME/.local/share") + set -gx XDG_STATE_HOME (test -n "$XDG_STATE_HOME"; and echo $XDG_STATE_HOME; or echo "$HOME/.local/state") + set -gx XDG_RUNTIME_DIR (test -n "$XDG_RUNTIME_DIR"; and echo $XDG_RUNTIME_DIR; or hyde_runtime_dir) end function hyde_die @@ -61,18 +79,41 @@ function hyprland_has_lua return 1 end +# Mirrors the resolution order in pyutils/lua_env.py, so a runtime that is good +# enough to provision the environment is not rejected here. +function hyde_find_bin + for candidate in $argv + test -n "$candidate"; or continue + if hyde_has $candidate + echo $candidate + return 0 + end + end + return 1 +end + +function hyde_find_lua + hyde_find_bin $LUA lua lua5.5 lua5.4 lua5.3 +end + +function hyde_find_luarocks + hyde_find_bin $LUAROCKS luarocks luarocks-5.5 luarocks-5.4 luarocks-5.3 +end + function check_lua_runtime - hyde_has lua; or return 1 - hyde_has luarocks; or return 1 + set -l missing + hyde_find_lua >/dev/null; or set -a missing lua + hyde_find_luarocks >/dev/null; or set -a missing luarocks + if test (count $missing) -gt 0 + echo "Lua runtime incomplete, missing: $missing" >&2 + return 1 + end end function setup_lua_mode set -l cfg (find_hyde_lua) and set -gx HYPRLAND_CONFIG $cfg - check_lua_runtime; or begin - echo "Lua runtime incomplete" >&2 - return 1 - end + check_lua_runtime; or return 1 hyprland_has_lua; or begin echo "Hyprland lacks Lua support" >&2 return 1 @@ -82,9 +123,9 @@ function setup_lua_mode end function setup_session - set -q XDG_CURRENT_DESKTOP; or set -x XDG_CURRENT_DESKTOP "HyDE" - set -q XDG_SESSION_DESKTOP; or set -x XDG_SESSION_DESKTOP "HyDE" - set -q XDG_SESSION_TYPE; or set -x XDG_SESSION_TYPE "wayland" + set -gx XDG_CURRENT_DESKTOP (test -n "$XDG_CURRENT_DESKTOP"; and echo $XDG_CURRENT_DESKTOP; or echo "HyDE") + set -gx XDG_SESSION_DESKTOP (test -n "$XDG_SESSION_DESKTOP"; and echo $XDG_SESSION_DESKTOP; or echo "HyDE") + set -gx XDG_SESSION_TYPE (test -n "$XDG_SESSION_TYPE"; and echo $XDG_SESSION_TYPE; or echo "wayland") end function hyde_activate diff --git a/Configs/.local/lib/hyde/shutils/ocr.sh b/Configs/.local/lib/hyde/shutils/ocr.sh index 8914b877a1..73435c492f 100644 --- a/Configs/.local/lib/hyde/shutils/ocr.sh +++ b/Configs/.local/lib/hyde/shutils/ocr.sh @@ -35,6 +35,6 @@ ocr_extract() { ) printf "%s" "$tesseract_output" | wl-copy - notify-send -a "HyDE Alert" "$(echo -e "OCR: ${#tesseract_output} symbols recognized\n\nLanguages used ${tesseract_languages[@]/#/'\n '}")" -i "$image_path" -e -r 9 + notify-send -a "HyDE Alert" "$(echo -e "OCR: ${#tesseract_output} symbols recognized\n\nLanguages used ${tesseract_languages[*]/#/'\n '}")" -i "$image_path" -e -r 9 } diff --git a/Configs/.local/lib/hyde/system.monitor.sh b/Configs/.local/lib/hyde/system.monitor.sh index f268bd6467..40c7592cb6 100755 --- a/Configs/.local/lib/hyde/system.monitor.sh +++ b/Configs/.local/lib/hyde/system.monitor.sh @@ -60,9 +60,11 @@ for sysMon in "${!pkgChk[@]}"; do break fi if pkg_installed "${pkgChk[sysMon]}"; then - term=$(grep -E '^\s*'"$term" "$HOME/.config/hypr/keybindings.conf" | cut -d '=' -f2 | xargs) - term=${TERMINAL:-$term} - term=${SYSMONITOR_TERMINAL:-$term} + term=${SYSMONITOR_TERMINAL:-${TERMINAL}} + if [ -z "${term}" ]; then + print_log -warn "system.monitor" "no terminal configured, set [sysmonitor] terminal or TERMINAL" + continue + fi if $term "${pkgChk[sysMon]}"; then pid="$!" echo "$pid:::${pkgChk[sysMon]}" > "$pidFile" diff --git a/Configs/.local/lib/hyde/uv.lock b/Configs/.local/lib/hyde/uv.lock index 9654cc180a..3be71c4a14 100644 --- a/Configs/.local/lib/hyde/uv.lock +++ b/Configs/.local/lib/hyde/uv.lock @@ -496,10 +496,10 @@ requires-dist = [ { name = "pulsectl", specifier = "==24.12.0" }, { name = "pyamdgpuinfo", marker = "extra == 'amd'" }, { name = "pygobject", marker = "extra == 'wayland'" }, - { name = "pyprland", specifier = "==3.3.1" }, + { name = "pyprland", specifier = "==3.4.3" }, { name = "pyqt6", marker = "extra == 'wayland'" }, { name = "pywayland", marker = "extra == 'wayland'" }, - { name = "requests", specifier = "==2.33.0" }, + { name = "requests", specifier = "==2.34.2" }, { name = "uv", specifier = ">=0.1.0" }, { name = "websockets", specifier = ">=16.0" }, { name = "xdg-prefs", git = "https://github.com/rchaput/xdg-prefs" }, @@ -933,17 +933,17 @@ sdist = { url = "https://files.pythonhosted.org/packages/a2/80/09247a2be28af2c22 [[package]] name = "pyprland" -version = "3.3.1" +version = "3.4.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiofiles" }, { name = "aiohttp" }, { name = "pillow" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/31/e3/2347cbb911f84e093017c465171315b7b9fbc0bcc524b09bf9f00bf3f90a/pyprland-3.3.1.tar.gz", hash = "sha256:6aa4c5930d97a2dbe7fa11b230e62e8b6e53d5fdc1983ed8fa6e4b8d8f8fcc08", size = 17868420, upload-time = "2026-04-03T17:22:20.639Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1f/89/d959da9682621ac163cb909e637eaff36db25ffd4b2cfb1d874146d63d73/pyprland-3.4.3.tar.gz", hash = "sha256:8757db7f5b1e3abd7ea8d0d0b6b6aec2083bde886a633af63008c67a08530da5", size = 17881577, upload-time = "2026-06-29T19:32:11.685Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b6/dd/2880d07e3edd46b619901bbe36a0872b8170905d279c5417c9f66146ed44/pyprland-3.3.1-cp3-none-manylinux_2_17_x86_64.whl", hash = "sha256:b8c75c599b02592dcecc5f8eaa352a6f924298309539f8da4b45ed2ef6e4e4c3", size = 18769441, upload-time = "2026-04-03T17:22:11.621Z" }, - { url = "https://files.pythonhosted.org/packages/ff/01/6c420eae657b40c8ddc45dff8140b3bbfc09b4e4cabd5d5394be63a846d1/pyprland-3.3.1-py3-none-any.whl", hash = "sha256:f0d4a0ef07d45c2d5456a190588f14a9fd2b4484a003dc30d449909161b9bb0f", size = 18426892, upload-time = "2026-04-03T17:22:16.37Z" }, + { url = "https://files.pythonhosted.org/packages/d4/26/7f048ed55c08a209692333093629d5f19f1d9037ef79b738f0b57ad1e839/pyprland-3.4.3-cp3-none-manylinux_2_17_x86_64.whl", hash = "sha256:e5901713d0afb0a18721c8c336e1de53c6699f36fe4f6c16f040c0ab55ee3356", size = 18801385, upload-time = "2026-06-29T19:32:16.764Z" }, + { url = "https://files.pythonhosted.org/packages/c7/eb/b98ce39e8ee0eb96b30407bec4a8022eee9b0bb4029ceef9adc29bfa32f2/pyprland-3.4.3-py3-none-any.whl", hash = "sha256:7334032a2e37b129be600007022c24e647576b27e88de7099644ef276f1e95f2", size = 18436381, upload-time = "2026-06-29T19:32:20.97Z" }, ] [[package]] @@ -1067,7 +1067,7 @@ wheels = [ [[package]] name = "requests" -version = "2.33.0" +version = "2.34.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, @@ -1075,9 +1075,9 @@ dependencies = [ { name = "idna" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/34/64/8860370b167a9721e8956ae116825caff829224fbca0ca6e7bf8ddef8430/requests-2.33.0.tar.gz", hash = "sha256:c7ebc5e8b0f21837386ad0e1c8fe8b829fa5f544d8df3b2253bff14ef29d7652", size = 134232, upload-time = "2026-03-25T15:10:41.586Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz", hash = "sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed", size = 142856, upload-time = "2026-05-14T19:25:27.735Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/56/5d/c814546c2333ceea4ba42262d8c4d55763003e767fa169adc693bd524478/requests-2.33.0-py3-none-any.whl", hash = "sha256:3324635456fa185245e24865e810cecec7b4caf933d7eb133dcde67d48cee69b", size = 65017, upload-time = "2026-03-25T15:10:40.382Z" }, + { url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0", size = 73075, upload-time = "2026-05-14T19:25:26.443Z" }, ] [[package]] @@ -1138,61 +1138,101 @@ wheels = [ [[package]] name = "websockets" -version = "16.0" +version = "16.1.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/04/24/4b2031d72e840ce4c1ccb255f693b15c334757fc50023e4db9537080b8c4/websockets-16.0.tar.gz", hash = "sha256:5f6261a5e56e8d5c42a4497b364ea24d94d9563e8fbd44e78ac40879c60179b5", size = 179346, upload-time = "2026-01-10T09:23:47.181Z" } +sdist = { url = "https://files.pythonhosted.org/packages/21/f7/bc3a25c5ec26ce62ce487690becc2f3710bbc7b33338f005ad390db0b986/websockets-16.1.1.tar.gz", hash = "sha256:db234eda965dcce15df96bb9709f587cd87d4d52aaf0e80e2f34ec04c7670c57", size = 182204, upload-time = "2026-07-17T22:51:05.858Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f2/db/de907251b4ff46ae804ad0409809504153b3f30984daf82a1d84a9875830/websockets-16.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:31a52addea25187bde0797a97d6fc3d2f92b6f72a9370792d65a6e84615ac8a8", size = 177340, upload-time = "2026-01-10T09:22:34.539Z" }, - { url = "https://files.pythonhosted.org/packages/f3/fa/abe89019d8d8815c8781e90d697dec52523fb8ebe308bf11664e8de1877e/websockets-16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:417b28978cdccab24f46400586d128366313e8a96312e4b9362a4af504f3bbad", size = 175022, upload-time = "2026-01-10T09:22:36.332Z" }, - { url = "https://files.pythonhosted.org/packages/58/5d/88ea17ed1ded2079358b40d31d48abe90a73c9e5819dbcde1606e991e2ad/websockets-16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:af80d74d4edfa3cb9ed973a0a5ba2b2a549371f8a741e0800cb07becdd20f23d", size = 175319, upload-time = "2026-01-10T09:22:37.602Z" }, - { url = "https://files.pythonhosted.org/packages/d2/ae/0ee92b33087a33632f37a635e11e1d99d429d3d323329675a6022312aac2/websockets-16.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:08d7af67b64d29823fed316505a89b86705f2b7981c07848fb5e3ea3020c1abe", size = 184631, upload-time = "2026-01-10T09:22:38.789Z" }, - { url = "https://files.pythonhosted.org/packages/c8/c5/27178df583b6c5b31b29f526ba2da5e2f864ecc79c99dae630a85d68c304/websockets-16.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7be95cfb0a4dae143eaed2bcba8ac23f4892d8971311f1b06f3c6b78952ee70b", size = 185870, upload-time = "2026-01-10T09:22:39.893Z" }, - { url = "https://files.pythonhosted.org/packages/87/05/536652aa84ddc1c018dbb7e2c4cbcd0db884580bf8e95aece7593fde526f/websockets-16.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d6297ce39ce5c2e6feb13c1a996a2ded3b6832155fcfc920265c76f24c7cceb5", size = 185361, upload-time = "2026-01-10T09:22:41.016Z" }, - { url = "https://files.pythonhosted.org/packages/6d/e2/d5332c90da12b1e01f06fb1b85c50cfc489783076547415bf9f0a659ec19/websockets-16.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1c1b30e4f497b0b354057f3467f56244c603a79c0d1dafce1d16c283c25f6e64", size = 184615, upload-time = "2026-01-10T09:22:42.442Z" }, - { url = "https://files.pythonhosted.org/packages/77/fb/d3f9576691cae9253b51555f841bc6600bf0a983a461c79500ace5a5b364/websockets-16.0-cp311-cp311-win32.whl", hash = "sha256:5f451484aeb5cafee1ccf789b1b66f535409d038c56966d6101740c1614b86c6", size = 178246, upload-time = "2026-01-10T09:22:43.654Z" }, - { url = "https://files.pythonhosted.org/packages/54/67/eaff76b3dbaf18dcddabc3b8c1dba50b483761cccff67793897945b37408/websockets-16.0-cp311-cp311-win_amd64.whl", hash = "sha256:8d7f0659570eefb578dacde98e24fb60af35350193e4f56e11190787bee77dac", size = 178684, upload-time = "2026-01-10T09:22:44.941Z" }, - { url = "https://files.pythonhosted.org/packages/84/7b/bac442e6b96c9d25092695578dda82403c77936104b5682307bd4deb1ad4/websockets-16.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:71c989cbf3254fbd5e84d3bff31e4da39c43f884e64f2551d14bb3c186230f00", size = 177365, upload-time = "2026-01-10T09:22:46.787Z" }, - { url = "https://files.pythonhosted.org/packages/b0/fe/136ccece61bd690d9c1f715baaeefd953bb2360134de73519d5df19d29ca/websockets-16.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8b6e209ffee39ff1b6d0fa7bfef6de950c60dfb91b8fcead17da4ee539121a79", size = 175038, upload-time = "2026-01-10T09:22:47.999Z" }, - { url = "https://files.pythonhosted.org/packages/40/1e/9771421ac2286eaab95b8575b0cb701ae3663abf8b5e1f64f1fd90d0a673/websockets-16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:86890e837d61574c92a97496d590968b23c2ef0aeb8a9bc9421d174cd378ae39", size = 175328, upload-time = "2026-01-10T09:22:49.809Z" }, - { url = "https://files.pythonhosted.org/packages/18/29/71729b4671f21e1eaa5d6573031ab810ad2936c8175f03f97f3ff164c802/websockets-16.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9b5aca38b67492ef518a8ab76851862488a478602229112c4b0d58d63a7a4d5c", size = 184915, upload-time = "2026-01-10T09:22:51.071Z" }, - { url = "https://files.pythonhosted.org/packages/97/bb/21c36b7dbbafc85d2d480cd65df02a1dc93bf76d97147605a8e27ff9409d/websockets-16.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e0334872c0a37b606418ac52f6ab9cfd17317ac26365f7f65e203e2d0d0d359f", size = 186152, upload-time = "2026-01-10T09:22:52.224Z" }, - { url = "https://files.pythonhosted.org/packages/4a/34/9bf8df0c0cf88fa7bfe36678dc7b02970c9a7d5e065a3099292db87b1be2/websockets-16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a0b31e0b424cc6b5a04b8838bbaec1688834b2383256688cf47eb97412531da1", size = 185583, upload-time = "2026-01-10T09:22:53.443Z" }, - { url = "https://files.pythonhosted.org/packages/47/88/4dd516068e1a3d6ab3c7c183288404cd424a9a02d585efbac226cb61ff2d/websockets-16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:485c49116d0af10ac698623c513c1cc01c9446c058a4e61e3bf6c19dff7335a2", size = 184880, upload-time = "2026-01-10T09:22:55.033Z" }, - { url = "https://files.pythonhosted.org/packages/91/d6/7d4553ad4bf1c0421e1ebd4b18de5d9098383b5caa1d937b63df8d04b565/websockets-16.0-cp312-cp312-win32.whl", hash = "sha256:eaded469f5e5b7294e2bdca0ab06becb6756ea86894a47806456089298813c89", size = 178261, upload-time = "2026-01-10T09:22:56.251Z" }, - { url = "https://files.pythonhosted.org/packages/c3/f0/f3a17365441ed1c27f850a80b2bc680a0fa9505d733fe152fdf5e98c1c0b/websockets-16.0-cp312-cp312-win_amd64.whl", hash = "sha256:5569417dc80977fc8c2d43a86f78e0a5a22fee17565d78621b6bb264a115d4ea", size = 178693, upload-time = "2026-01-10T09:22:57.478Z" }, - { url = "https://files.pythonhosted.org/packages/cc/9c/baa8456050d1c1b08dd0ec7346026668cbc6f145ab4e314d707bb845bf0d/websockets-16.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:878b336ac47938b474c8f982ac2f7266a540adc3fa4ad74ae96fea9823a02cc9", size = 177364, upload-time = "2026-01-10T09:22:59.333Z" }, - { url = "https://files.pythonhosted.org/packages/7e/0c/8811fc53e9bcff68fe7de2bcbe75116a8d959ac699a3200f4847a8925210/websockets-16.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:52a0fec0e6c8d9a784c2c78276a48a2bdf099e4ccc2a4cad53b27718dbfd0230", size = 175039, upload-time = "2026-01-10T09:23:01.171Z" }, - { url = "https://files.pythonhosted.org/packages/aa/82/39a5f910cb99ec0b59e482971238c845af9220d3ab9fa76dd9162cda9d62/websockets-16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e6578ed5b6981005df1860a56e3617f14a6c307e6a71b4fff8c48fdc50f3ed2c", size = 175323, upload-time = "2026-01-10T09:23:02.341Z" }, - { url = "https://files.pythonhosted.org/packages/bd/28/0a25ee5342eb5d5f297d992a77e56892ecb65e7854c7898fb7d35e9b33bd/websockets-16.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:95724e638f0f9c350bb1c2b0a7ad0e83d9cc0c9259f3ea94e40d7b02a2179ae5", size = 184975, upload-time = "2026-01-10T09:23:03.756Z" }, - { url = "https://files.pythonhosted.org/packages/f9/66/27ea52741752f5107c2e41fda05e8395a682a1e11c4e592a809a90c6a506/websockets-16.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0204dc62a89dc9d50d682412c10b3542d748260d743500a85c13cd1ee4bde82", size = 186203, upload-time = "2026-01-10T09:23:05.01Z" }, - { url = "https://files.pythonhosted.org/packages/37/e5/8e32857371406a757816a2b471939d51c463509be73fa538216ea52b792a/websockets-16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:52ac480f44d32970d66763115edea932f1c5b1312de36df06d6b219f6741eed8", size = 185653, upload-time = "2026-01-10T09:23:06.301Z" }, - { url = "https://files.pythonhosted.org/packages/9b/67/f926bac29882894669368dc73f4da900fcdf47955d0a0185d60103df5737/websockets-16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6e5a82b677f8f6f59e8dfc34ec06ca6b5b48bc4fcda346acd093694cc2c24d8f", size = 184920, upload-time = "2026-01-10T09:23:07.492Z" }, - { url = "https://files.pythonhosted.org/packages/3c/a1/3d6ccdcd125b0a42a311bcd15a7f705d688f73b2a22d8cf1c0875d35d34a/websockets-16.0-cp313-cp313-win32.whl", hash = "sha256:abf050a199613f64c886ea10f38b47770a65154dc37181bfaff70c160f45315a", size = 178255, upload-time = "2026-01-10T09:23:09.245Z" }, - { url = "https://files.pythonhosted.org/packages/6b/ae/90366304d7c2ce80f9b826096a9e9048b4bb760e44d3b873bb272cba696b/websockets-16.0-cp313-cp313-win_amd64.whl", hash = "sha256:3425ac5cf448801335d6fdc7ae1eb22072055417a96cc6b31b3861f455fbc156", size = 178689, upload-time = "2026-01-10T09:23:10.483Z" }, - { url = "https://files.pythonhosted.org/packages/f3/1d/e88022630271f5bd349ed82417136281931e558d628dd52c4d8621b4a0b2/websockets-16.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8cc451a50f2aee53042ac52d2d053d08bf89bcb31ae799cb4487587661c038a0", size = 177406, upload-time = "2026-01-10T09:23:12.178Z" }, - { url = "https://files.pythonhosted.org/packages/f2/78/e63be1bf0724eeb4616efb1ae1c9044f7c3953b7957799abb5915bffd38e/websockets-16.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:daa3b6ff70a9241cf6c7fc9e949d41232d9d7d26fd3522b1ad2b4d62487e9904", size = 175085, upload-time = "2026-01-10T09:23:13.511Z" }, - { url = "https://files.pythonhosted.org/packages/bb/f4/d3c9220d818ee955ae390cf319a7c7a467beceb24f05ee7aaaa2414345ba/websockets-16.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:fd3cb4adb94a2a6e2b7c0d8d05cb94e6f1c81a0cf9dc2694fb65c7e8d94c42e4", size = 175328, upload-time = "2026-01-10T09:23:14.727Z" }, - { url = "https://files.pythonhosted.org/packages/63/bc/d3e208028de777087e6fb2b122051a6ff7bbcca0d6df9d9c2bf1dd869ae9/websockets-16.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:781caf5e8eee67f663126490c2f96f40906594cb86b408a703630f95550a8c3e", size = 185044, upload-time = "2026-01-10T09:23:15.939Z" }, - { url = "https://files.pythonhosted.org/packages/ad/6e/9a0927ac24bd33a0a9af834d89e0abc7cfd8e13bed17a86407a66773cc0e/websockets-16.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:caab51a72c51973ca21fa8a18bd8165e1a0183f1ac7066a182ff27107b71e1a4", size = 186279, upload-time = "2026-01-10T09:23:17.148Z" }, - { url = "https://files.pythonhosted.org/packages/b9/ca/bf1c68440d7a868180e11be653c85959502efd3a709323230314fda6e0b3/websockets-16.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:19c4dc84098e523fd63711e563077d39e90ec6702aff4b5d9e344a60cb3c0cb1", size = 185711, upload-time = "2026-01-10T09:23:18.372Z" }, - { url = "https://files.pythonhosted.org/packages/c4/f8/fdc34643a989561f217bb477cbc47a3a07212cbda91c0e4389c43c296ebf/websockets-16.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a5e18a238a2b2249c9a9235466b90e96ae4795672598a58772dd806edc7ac6d3", size = 184982, upload-time = "2026-01-10T09:23:19.652Z" }, - { url = "https://files.pythonhosted.org/packages/dd/d1/574fa27e233764dbac9c52730d63fcf2823b16f0856b3329fc6268d6ae4f/websockets-16.0-cp314-cp314-win32.whl", hash = "sha256:a069d734c4a043182729edd3e9f247c3b2a4035415a9172fd0f1b71658a320a8", size = 177915, upload-time = "2026-01-10T09:23:21.458Z" }, - { url = "https://files.pythonhosted.org/packages/8a/f1/ae6b937bf3126b5134ce1f482365fde31a357c784ac51852978768b5eff4/websockets-16.0-cp314-cp314-win_amd64.whl", hash = "sha256:c0ee0e63f23914732c6d7e0cce24915c48f3f1512ec1d079ed01fc629dab269d", size = 178381, upload-time = "2026-01-10T09:23:22.715Z" }, - { url = "https://files.pythonhosted.org/packages/06/9b/f791d1db48403e1f0a27577a6beb37afae94254a8c6f08be4a23e4930bc0/websockets-16.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:a35539cacc3febb22b8f4d4a99cc79b104226a756aa7400adc722e83b0d03244", size = 177737, upload-time = "2026-01-10T09:23:24.523Z" }, - { url = "https://files.pythonhosted.org/packages/bd/40/53ad02341fa33b3ce489023f635367a4ac98b73570102ad2cdd770dacc9a/websockets-16.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:b784ca5de850f4ce93ec85d3269d24d4c82f22b7212023c974c401d4980ebc5e", size = 175268, upload-time = "2026-01-10T09:23:25.781Z" }, - { url = "https://files.pythonhosted.org/packages/74/9b/6158d4e459b984f949dcbbb0c5d270154c7618e11c01029b9bbd1bb4c4f9/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:569d01a4e7fba956c5ae4fc988f0d4e187900f5497ce46339c996dbf24f17641", size = 175486, upload-time = "2026-01-10T09:23:27.033Z" }, - { url = "https://files.pythonhosted.org/packages/e5/2d/7583b30208b639c8090206f95073646c2c9ffd66f44df967981a64f849ad/websockets-16.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:50f23cdd8343b984957e4077839841146f67a3d31ab0d00e6b824e74c5b2f6e8", size = 185331, upload-time = "2026-01-10T09:23:28.259Z" }, - { url = "https://files.pythonhosted.org/packages/45/b0/cce3784eb519b7b5ad680d14b9673a31ab8dcb7aad8b64d81709d2430aa8/websockets-16.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:152284a83a00c59b759697b7f9e9cddf4e3c7861dd0d964b472b70f78f89e80e", size = 186501, upload-time = "2026-01-10T09:23:29.449Z" }, - { url = "https://files.pythonhosted.org/packages/19/60/b8ebe4c7e89fb5f6cdf080623c9d92789a53636950f7abacfc33fe2b3135/websockets-16.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bc59589ab64b0022385f429b94697348a6a234e8ce22544e3681b2e9331b5944", size = 186062, upload-time = "2026-01-10T09:23:31.368Z" }, - { url = "https://files.pythonhosted.org/packages/88/a8/a080593f89b0138b6cba1b28f8df5673b5506f72879322288b031337c0b8/websockets-16.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:32da954ffa2814258030e5a57bc73a3635463238e797c7375dc8091327434206", size = 185356, upload-time = "2026-01-10T09:23:32.627Z" }, - { url = "https://files.pythonhosted.org/packages/c2/b6/b9afed2afadddaf5ebb2afa801abf4b0868f42f8539bfe4b071b5266c9fe/websockets-16.0-cp314-cp314t-win32.whl", hash = "sha256:5a4b4cc550cb665dd8a47f868c8d04c8230f857363ad3c9caf7a0c3bf8c61ca6", size = 178085, upload-time = "2026-01-10T09:23:33.816Z" }, - { url = "https://files.pythonhosted.org/packages/9f/3e/28135a24e384493fa804216b79a6a6759a38cc4ff59118787b9fb693df93/websockets-16.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b14dc141ed6d2dde437cddb216004bcac6a1df0935d79656387bd41632ba0bbd", size = 178531, upload-time = "2026-01-10T09:23:35.016Z" }, - { url = "https://files.pythonhosted.org/packages/72/07/c98a68571dcf256e74f1f816b8cc5eae6eb2d3d5cfa44d37f801619d9166/websockets-16.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:349f83cd6c9a415428ee1005cadb5c2c56f4389bc06a9af16103c3bc3dcc8b7d", size = 174947, upload-time = "2026-01-10T09:23:36.166Z" }, - { url = "https://files.pythonhosted.org/packages/7e/52/93e166a81e0305b33fe416338be92ae863563fe7bce446b0f687b9df5aea/websockets-16.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:4a1aba3340a8dca8db6eb5a7986157f52eb9e436b74813764241981ca4888f03", size = 175260, upload-time = "2026-01-10T09:23:37.409Z" }, - { url = "https://files.pythonhosted.org/packages/56/0c/2dbf513bafd24889d33de2ff0368190a0e69f37bcfa19009ef819fe4d507/websockets-16.0-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f4a32d1bd841d4bcbffdcb3d2ce50c09c3909fbead375ab28d0181af89fd04da", size = 176071, upload-time = "2026-01-10T09:23:39.158Z" }, - { url = "https://files.pythonhosted.org/packages/a5/8f/aea9c71cc92bf9b6cc0f7f70df8f0b420636b6c96ef4feee1e16f80f75dd/websockets-16.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0298d07ee155e2e9fda5be8a9042200dd2e3bb0b8a38482156576f863a9d457c", size = 176968, upload-time = "2026-01-10T09:23:41.031Z" }, - { url = "https://files.pythonhosted.org/packages/9a/3f/f70e03f40ffc9a30d817eef7da1be72ee4956ba8d7255c399a01b135902a/websockets-16.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:a653aea902e0324b52f1613332ddf50b00c06fdaf7e92624fbf8c77c78fa5767", size = 178735, upload-time = "2026-01-10T09:23:42.259Z" }, - { url = "https://files.pythonhosted.org/packages/6f/28/258ebab549c2bf3e64d2b0217b973467394a9cea8c42f70418ca2c5d0d2e/websockets-16.0-py3-none-any.whl", hash = "sha256:1637db62fad1dc833276dded54215f2c7fa46912301a24bd94d45d46a011ceec", size = 171598, upload-time = "2026-01-10T09:23:45.395Z" }, + { url = "https://files.pythonhosted.org/packages/2b/03/47debfe28e9d6d354be5d777b67fd44c359b9eb299a5d103500bd7cc3e37/websockets-16.1.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d0fcf657e9f13ff4b177960ab2200237b12994232dfb6df16f1cfe1d4339f93c", size = 179566, upload-time = "2026-07-17T22:48:49.596Z" }, + { url = "https://files.pythonhosted.org/packages/72/93/31efa1ed78c17e5cfc229fd449e3966e1b9cc15753204cd585cc8dd01f4a/websockets-16.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b852788aa51764e2d8e4cf5493d559326bcae5e38d16ba25ffa322b034df272a", size = 177250, upload-time = "2026-07-17T22:48:50.942Z" }, + { url = "https://files.pythonhosted.org/packages/01/4a/542378ab3972b0c1cf1df3df3eff9591cea0d30c58c3aa3c4ddbc244e787/websockets-16.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1427fb4cf0d72f66333e2cacc3ff5f575bf2d7008166ce991a4a470b21d51a22", size = 177528, upload-time = "2026-07-17T22:48:52.59Z" }, + { url = "https://files.pythonhosted.org/packages/33/d9/162321f63c7eed558e9e1798ed7a1e34a4f6dab51f35419e4ed7a4907979/websockets-16.1.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:da4ca1a9d72f9030b3146b8d7022719a9f3d478f61efe6f7dd51d243f61c51b2", size = 186859, upload-time = "2026-07-17T22:48:53.915Z" }, + { url = "https://files.pythonhosted.org/packages/de/09/87df740f7430ce564bd52402e9c9458d4d0459cc7d2ee29e530c8204851b/websockets-16.1.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:86d7f0f8bdb25d2c632b72527325e4776430fd5bc61b9118de4e2b8ddb5f5b01", size = 188095, upload-time = "2026-07-17T22:48:55.384Z" }, + { url = "https://files.pythonhosted.org/packages/d2/12/3d2703af7cc095f3c81904c92208cc1ae79affbc67376944b50ee9301f73/websockets-16.1.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7dfcad78ea1492ee3a9ec765cb7f51bbc17d477107aaf6b22abf7b2558d1c5a0", size = 191385, upload-time = "2026-07-17T22:48:56.742Z" }, + { url = "https://files.pythonhosted.org/packages/1d/69/986aa0234a964a00f5149cfc46e136e96c8faad1c783474550f40d31aef4/websockets-16.1.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fb9a0a6dc3d1b3986cb88091b6899f0396651e0f74e2c9766ab8d6ffc3842e29", size = 188653, upload-time = "2026-07-17T22:48:58.134Z" }, + { url = "https://files.pythonhosted.org/packages/35/6b/10f9d03e3970a69ba67bd3b46b87a929b586d0300fadbfe14f57c1f85490/websockets-16.1.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29dfa8114c4a620c69591c5973860f768eac29d3fd6904f37f34266cb219c512", size = 187426, upload-time = "2026-07-17T22:48:59.515Z" }, + { url = "https://files.pythonhosted.org/packages/56/db/bb3aad62bf63d8bb3f0634b2eabffcfb3677a34bd19492110ff6869cf703/websockets-16.1.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6ff9417c0ada4d0f7d212f928303e5579bdf3ace4c802fa4afabb30995da58c3", size = 184882, upload-time = "2026-07-17T22:49:00.916Z" }, + { url = "https://files.pythonhosted.org/packages/6c/4c/c09a2ea9bfbeccce52fdc383e5f28af4bc8843338aabac28c81489af6120/websockets-16.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fe0b50da2d84535fb4f7b4bfa951280f97ce3d558a0443b541166d609e67b57", size = 187584, upload-time = "2026-07-17T22:49:02.283Z" }, + { url = "https://files.pythonhosted.org/packages/c7/8b/31bb4eb4d9eaacf1fdd39d115772a8aeaedfc19b5dc262e57ffbc8a9d42c/websockets-16.1.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:34420aaa64440ebd51ac72ca8a45ef4626429438c9b02e633ae412ed43f925d3", size = 186174, upload-time = "2026-07-17T22:49:03.973Z" }, + { url = "https://files.pythonhosted.org/packages/2f/e4/dc02d725610a1ad49e193ef91a548194d71bdc6cdf27da83067dd1f73995/websockets-16.1.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a6a61aff018180c9c50b7b0da33bfd29d378af3497429c95006c589a23a11648", size = 187986, upload-time = "2026-07-17T22:49:05.553Z" }, + { url = "https://files.pythonhosted.org/packages/e0/73/30ed84c8bfd14c73d4af29d5ed9323c3073b48e0b7b23b67070f4e7fd59b/websockets-16.1.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:04fd29a0e2fe9414a95b00e92c67ae51bf900c50c0f8a4b2dafdad621f49ea1d", size = 185565, upload-time = "2026-07-17T22:49:06.959Z" }, + { url = "https://files.pythonhosted.org/packages/7d/d3/4be8d4959f51e31b4f8fc0ece12b45bd3b6c0d15ea23b9990d9c11fc805f/websockets-16.1.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5c31aa7e39ee3e8a358573257f1c0bb5c52430d1b637030dd9c8cc2c282926be", size = 186598, upload-time = "2026-07-17T22:49:08.293Z" }, + { url = "https://files.pythonhosted.org/packages/26/fa/abb38597a52d84ed9cfacadc7a0c6f2db282c0ab23cdf72b58a666a21227/websockets-16.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d14bfb217eb4701e850f1525c9d29d79c44794cdf1c299ead25f39f8c78dea81", size = 186834, upload-time = "2026-07-17T22:49:09.766Z" }, + { url = "https://files.pythonhosted.org/packages/59/80/1119ad08a228b90c4eb77fbe48df7836731a605f5f881ba701ca826a4a65/websockets-16.1.1-cp311-cp311-win32.whl", hash = "sha256:2e28e602bb13da44fbe518c1781a88e3b9d4c3d48d02c9bad83e546164336f57", size = 179940, upload-time = "2026-07-17T22:49:11.196Z" }, + { url = "https://files.pythonhosted.org/packages/71/b2/e511c1c6f64a95c2f3fc54bffda0e14eaa7e9442be605c29270f7589b918/websockets-16.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:7421fad442de870a8cbf2287d1cad7e706ece0dbfeba5e911df132cbdc1cb56a", size = 180239, upload-time = "2026-07-17T22:49:12.519Z" }, + { url = "https://files.pythonhosted.org/packages/17/9d/681cda21c9eee743203a6cb79b9d3d05adad9aa60ec660c6c9bf4dd619ca/websockets-16.1.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:cc97814dfb786a83b6e2dc2e79351e1b83e6d715647d6887fcabd83026417a00", size = 179600, upload-time = "2026-07-17T22:49:13.92Z" }, + { url = "https://files.pythonhosted.org/packages/fb/8d/6195a88b45e8d2a8f745fc2046e36f885a3c9763e6767d2c46229bf9510c/websockets-16.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e047dc87ef7ca50f4d309bf775ad4a71711c58556d75d7bd0604b2317f43e94b", size = 177272, upload-time = "2026-07-17T22:49:15.453Z" }, + { url = "https://files.pythonhosted.org/packages/73/e3/fe2d498c64dea0095c9a9f9a351af4cd6eef31b618395582bc1f38ba45ff/websockets-16.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:01fbdcbac298efe19360b94bc0039c8f746f0220ba570f327577bfee81059175", size = 177542, upload-time = "2026-07-17T22:49:16.875Z" }, + { url = "https://files.pythonhosted.org/packages/fe/ed/f1831681fce0e3242346e5458486003c5f124ed69e5e0b847fd029db4973/websockets-16.1.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0f62863e8a00a6d33c3d6566ec0b89f23787b747ffe0c3bc71ec0e76b82c94b1", size = 187137, upload-time = "2026-07-17T22:49:18.323Z" }, + { url = "https://files.pythonhosted.org/packages/6f/79/4ff9dcc1bb46f6b4c536936dde1fd60f9b564f3304307274db97f4c9496d/websockets-16.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8087e82f842609734c9b5a1330464f8e94e346ba0e18c832c08bafa4b0d63c15", size = 188374, upload-time = "2026-07-17T22:49:19.65Z" }, + { url = "https://files.pythonhosted.org/packages/62/c3/5c49b6efb36cab733d23773f6de575e1dba65736ead17d5d2b2a1daef779/websockets-16.1.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2bb5d041a8307d2e18782e7ce777f6fdb1e8c2f5d09291484b18c294b789d9aa", size = 191155, upload-time = "2026-07-17T22:49:21.331Z" }, + { url = "https://files.pythonhosted.org/packages/6e/f6/56ccceda3a4838d18f1d40821480da4775397e8b1eecf4031e20c50e2e90/websockets-16.1.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1db4de4a0e95673f7545d393c49eeb0c2f18ac1ef93073218c79d5cdb2ee75ab", size = 189011, upload-time = "2026-07-17T22:49:22.889Z" }, + { url = "https://files.pythonhosted.org/packages/86/d6/ad5286241a2bce1107e2798d3bfbd62cf79aee167bdb654f8cb1e9dbf949/websockets-16.1.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f17dbe07eb3ea7f99e4df9b7e0efefe80fbf30d37a8cc4d561a0aed310bc8847", size = 187766, upload-time = "2026-07-17T22:49:24.339Z" }, + { url = "https://files.pythonhosted.org/packages/bc/67/d65c970b7e347fdca69479beb7811c2060529956730a7a4e3ae7c66b0e31/websockets-16.1.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4b57693728576d84ede0a77987ab16881b783d2cd9f1dc180a8fbbc3f79c4428", size = 185173, upload-time = "2026-07-17T22:49:25.743Z" }, + { url = "https://files.pythonhosted.org/packages/1d/5b/14af3cd4ee69d8ea9baca58f3dc3cfb1ba78332a347fd478cb096549d60e/websockets-16.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2a636ff1e7a5c4edf71ef0e79adae7f25dba93b4fcbe3dc958733477ffeb0eaf", size = 187809, upload-time = "2026-07-17T22:49:27.147Z" }, + { url = "https://files.pythonhosted.org/packages/7b/11/be301710d70de97e3e7b3586e6d492c9c06d6a61bf1c2202c36cf0c75607/websockets-16.1.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:d6bec75c290fe484a8ba4cacdf838501e17c06ecfbbf31eede81a9e431bd7751", size = 186412, upload-time = "2026-07-17T22:49:28.611Z" }, + { url = "https://files.pythonhosted.org/packages/db/07/fe1435bf6fe738a3d3b54dbe0c18dabf12cba4d909ac8b58b539ce27c1f4/websockets-16.1.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:54509b8e92fee4453e152b7558ddef37ce9705a044922f2095a6105e3f80c96f", size = 188290, upload-time = "2026-07-17T22:49:29.965Z" }, + { url = "https://files.pythonhosted.org/packages/8a/0a/81f394aff8efcbb01208c1ced77df0a3c7fcce584a88c7273663697946c2/websockets-16.1.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:f0aa4aad3b1b69ad3fd85a0fd0952ec64331c762bd77ec51cc814170873890b2", size = 185844, upload-time = "2026-07-17T22:49:31.447Z" }, + { url = "https://files.pythonhosted.org/packages/39/5c/dd485b995473f415510251fe9bd708f2d24458f439fce958daf8d66dc7c6/websockets-16.1.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:42290eb6db4ccaca7012656738214f8514082fb6fa40cdeb61bb9a471b52e383", size = 186823, upload-time = "2026-07-17T22:49:33.104Z" }, + { url = "https://files.pythonhosted.org/packages/9d/0b/f78de76ff446f1e66af12b43c48a35f31744de93cfdec2f4ea67d5d7bbf1/websockets-16.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:53260c8930da5771cec89439bff99c20c8cb03ddb9588b980697355a83cd4bd3", size = 187102, upload-time = "2026-07-17T22:49:34.616Z" }, + { url = "https://files.pythonhosted.org/packages/37/a1/4cf892007778eaf84ad162bfc98046e0ed89b63ac55949e3236626b2a23f/websockets-16.1.1-cp312-cp312-win32.whl", hash = "sha256:1d27fa8462ad6a1cb36206a3d0640b2333340def181fae11ed7f9adeaa5c0747", size = 179943, upload-time = "2026-07-17T22:49:36.213Z" }, + { url = "https://files.pythonhosted.org/packages/d9/de/6abe251d28c3a3f217096575400b27750b18e0b1d2fff3a2a239960fea07/websockets-16.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:b436f6ec4fc3a6b4237c84d3f83170ed2b40bb584222f0ac47a0c8a5921980c7", size = 180243, upload-time = "2026-07-17T22:49:37.626Z" }, + { url = "https://files.pythonhosted.org/packages/ce/fd/6ec6c6d2850aea25b1b2aa9901a016980bb87d01e89b3eb00470b1b5d471/websockets-16.1.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ab59169ace05dcb49a1d4118f0bde139557adf45091bd85747e36bf5de984dd1", size = 179587, upload-time = "2026-07-17T22:49:38.959Z" }, + { url = "https://files.pythonhosted.org/packages/5f/d8/1d299d2dd34087db39831a34cc645ef8a6f89d78efada6983093513cd81c/websockets-16.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5e3b7d601f6f84156b08cc4a5e541c2b50ad7b36cfc302b657a12477c904a5df", size = 177272, upload-time = "2026-07-17T22:49:40.293Z" }, + { url = "https://files.pythonhosted.org/packages/3d/86/0a70d3ae2f0f2256bb41302d9804dbca65d4360281e7feb3e1f94102ac46/websockets-16.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cd2ca96a082a36964aca83e992f72abeb61b7306c1a6cba4c7d06a7b93750cac", size = 177530, upload-time = "2026-07-17T22:49:41.786Z" }, + { url = "https://files.pythonhosted.org/packages/b5/c2/c676c69444d9db448b3f0a55a98dcc534affce0bce961d9d2f0b8499b10a/websockets-16.1.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f5d497865f05bb222cab7016c6034542e84e5f29f49c6fd3f4939cda7197b5b8", size = 187197, upload-time = "2026-07-17T22:49:43.658Z" }, + { url = "https://files.pythonhosted.org/packages/0b/13/88137fbaf726ebe29d62c1117fa11fa2bbb6209dc79d4ad738efbe36a2aa/websockets-16.1.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bae954c382e013d5ea5b190d2830526bfa45ad121c326da0049b8c769f185db6", size = 188433, upload-time = "2026-07-17T22:49:45.147Z" }, + { url = "https://files.pythonhosted.org/packages/01/6d/46c2f2ce6751cb26f39293e1ecbf8544cb01321397cd476c2756b98c216d/websockets-16.1.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e09f753a169951eb4f28c2c774f71069304f66e7277e0f5a2892423599cfa854", size = 189868, upload-time = "2026-07-17T22:49:46.581Z" }, + { url = "https://files.pythonhosted.org/packages/29/2b/170a9e8097636cfde4dc3c592b6e00b18a44a2f5407606d96ca542dd5838/websockets-16.1.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:024193f8551a2b0eafbdd160911012c4e6c228c28430c84433253299a9e42d6a", size = 189059, upload-time = "2026-07-17T22:49:47.972Z" }, + { url = "https://files.pythonhosted.org/packages/a7/48/f0d4ebc9ab4b473b8861b9e20fdb663d515d42f7befdf62cdb60fee7a1ec/websockets-16.1.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:aabe464bfd13bd25f4821faf111da6fefdc389f870265a53105580e45b0a2e49", size = 187814, upload-time = "2026-07-17T22:49:49.344Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ba/39a41d3ae8e72696a9492581900611c5a91e2b07563b0bcd2523adea9854/websockets-16.1.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a28fcbc9b6baf54a2e23f8655f308e4ccc6afdd7266f8fe7954f320dcda0f785", size = 185229, upload-time = "2026-07-17T22:49:50.787Z" }, + { url = "https://files.pythonhosted.org/packages/3c/36/ac15b604f850d1907f0a85ed721cefe47cd45034b3620069b829746cccbe/websockets-16.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:79eace538c6a97e96d0d03d4f9d314f9677f5ed85a8a984992ffd90b13cb8a56", size = 187874, upload-time = "2026-07-17T22:49:52.228Z" }, + { url = "https://files.pythonhosted.org/packages/a8/f3/3fbd5d71d59299c3770faa5884d4f45070236ca5a35ab3a61830812c409a/websockets-16.1.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:496af849a472b531f758dbd4d61338f5000538cb1a7b3d20d9d32a264517f509", size = 186469, upload-time = "2026-07-17T22:49:53.776Z" }, + { url = "https://files.pythonhosted.org/packages/b4/fc/dd90349bba58af2a53ef2ddd9c32716c81eb6d59a0687939fff561860878/websockets-16.1.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5283810d2646741a0d8da2aa733d6aefa0545809afccb2a5d105a26bc45125f1", size = 188347, upload-time = "2026-07-17T22:49:55.202Z" }, + { url = "https://files.pythonhosted.org/packages/4c/f3/f73ba86427682da59b78c11d77ba56d5b801c32e84afe79b274bbd6a9bb2/websockets-16.1.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:4e3b680b1e0a27457e727a0d572fd81dffa87b6dbf8b228ab57da64f7d85aead", size = 185903, upload-time = "2026-07-17T22:49:56.75Z" }, + { url = "https://files.pythonhosted.org/packages/34/7c/f95eb20e80104173b3a0a092291f89ea4047ef6e608e0a57ca06eb14eecb/websockets-16.1.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:69159730a823dde3ea8d08783e8d47ef135a6d7e8d44eb127e32b321c9db8e3e", size = 186855, upload-time = "2026-07-17T22:49:58.467Z" }, + { url = "https://files.pythonhosted.org/packages/b0/35/dd875b3e050ff232d60fa377707f890e369f74d134f1be32e8f68879747c/websockets-16.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ed5bb271084b46530ee2ddc0410537a9961152c5ccba2fc98c5276d992ccba87", size = 187140, upload-time = "2026-07-17T22:50:00.016Z" }, + { url = "https://files.pythonhosted.org/packages/e8/dc/5cbfcb41824502f6af93b8f3943a4d06c67c23c7d2e31eb18748c4a5b2a7/websockets-16.1.1-cp313-cp313-win32.whl", hash = "sha256:cfb70b4eb56cac4da0a83588f3ad50d46beb0690391082f3d4e2d488c70b68ea", size = 179928, upload-time = "2026-07-17T22:50:01.685Z" }, + { url = "https://files.pythonhosted.org/packages/b0/c1/71e5deb5b7f8f226997ab64908c184ac3105c0155ce2d486f318e5dd08a8/websockets-16.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:d9531d9cbeac99af6f038fb1bc351403531f7d634a2c2e10e2f7c854c6ed5b68", size = 180242, upload-time = "2026-07-17T22:50:03.117Z" }, + { url = "https://files.pythonhosted.org/packages/73/a2/ba78a164eeea4620df4a4df4bd2ed6017438c4655cc0f36f2c0bc0432355/websockets-16.1.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:443aefe96b7fdb132e2a70806cca1f2af49bb3f28e47abcd7c2e9dcf4d8fa1b8", size = 179635, upload-time = "2026-07-17T22:50:05.001Z" }, + { url = "https://files.pythonhosted.org/packages/b9/08/d26d7a7628cd4ac34cbbdb63ac80914ca842ed8e42938c40a53567806df3/websockets-16.1.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:6456ff333092d509127d75a638cb411afae8ff17f092635015d1902efec8a293", size = 177320, upload-time = "2026-07-17T22:50:06.427Z" }, + { url = "https://files.pythonhosted.org/packages/0f/45/ebec83e6269536aa5932533c67b0af5c781f3e73fdbcd68672dcf43f4f44/websockets-16.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:fce6c48559c86d1ac3632ccb1bebc7d5442fbe79bd9bb0e40379ee54be2a4051", size = 177544, upload-time = "2026-07-17T22:50:07.834Z" }, + { url = "https://files.pythonhosted.org/packages/c9/d5/abc614d2297f6c1c3e01e61260364457a47c25cc1cf6a879038902bc6aa8/websockets-16.1.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:92b820d345f7a3fc7b8163949ee92df910f290c3fc517b3d5301c78065adafe1", size = 187270, upload-time = "2026-07-17T22:50:09.275Z" }, + { url = "https://files.pythonhosted.org/packages/52/71/4c99af3b87dff1b2927981f6876607d4acb45338c665242168d3982f7758/websockets-16.1.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2a606d9c24035242a3e256e9d5b77ed9cd6bccfcb7cf993e5ca3c0f6f68fb6a7", size = 188509, upload-time = "2026-07-17T22:50:10.722Z" }, + { url = "https://files.pythonhosted.org/packages/9b/b4/5c8ca14b0df7eb84ed0524165c5359150210140817a3312aee57bf62a1cf/websockets-16.1.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:414e596c75f74e0994084694189d7dc9229fb278e33064d6784b73ffbba3ca31", size = 189882, upload-time = "2026-07-17T22:50:12.293Z" }, + { url = "https://files.pythonhosted.org/packages/25/c1/bedfba9e70557129cb8083748d167bdcc01483dedf0f0df143676df05cbe/websockets-16.1.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:536676848fc5961aca9d20389951f59169508f765637a172403dc5434d722fa0", size = 189114, upload-time = "2026-07-17T22:50:13.789Z" }, + { url = "https://files.pythonhosted.org/packages/df/09/aa835b2787835aebd839114be5de51b797cb480b63ba42b26d34dfe147cb/websockets-16.1.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:97fd3a0e8b53efa41970ac1dff3d8cf0d2884cadeb4caaf95db7ad1526926ee3", size = 187861, upload-time = "2026-07-17T22:50:15.179Z" }, + { url = "https://files.pythonhosted.org/packages/20/26/f6408330694dbc9830857d9d23bc14ac4f6875127a480cfdda8d5ca21198/websockets-16.1.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7b1b19636af86a3c7995d4d028dbe376f39b4bf31541146f9c123582a6c94562", size = 185286, upload-time = "2026-07-17T22:50:16.741Z" }, + { url = "https://files.pythonhosted.org/packages/17/9a/e0675e70dd8a80762cf35bb18799d3f290a4890ffe6439bc51d222796083/websockets-16.1.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:41c8e77f17294c0ac18008a7309b99b34ee72247ef10b6dff4c3f8b5ac29896b", size = 187935, upload-time = "2026-07-17T22:50:18.213Z" }, + { url = "https://files.pythonhosted.org/packages/33/c1/3234cfb86afde01b81e9bddcc6e534c440975d60a13991259e833069ab3e/websockets-16.1.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:9f63bcef7f4b02b06b35fc01c93b96c43b5e88e1e8868676caacf493d5a31f3a", size = 186444, upload-time = "2026-07-17T22:50:19.67Z" }, + { url = "https://files.pythonhosted.org/packages/89/87/9c15206e1d778923d8daa9657de07aa62ea815e13448319c98458c37b281/websockets-16.1.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:dab9eb87869da2d6ed3af3f3adf28414baae6ec9d4df355ffc18889132f3436c", size = 188409, upload-time = "2026-07-17T22:50:21.28Z" }, + { url = "https://files.pythonhosted.org/packages/f2/00/cf5de5c67676de2d3eef8b2a518f168f6796595447a5b7161ba0d012915c/websockets-16.1.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:43e3a9fdd7cbf7ba6040c31fae0faf84ca1474fef777c4e37912f1540f854499", size = 185958, upload-time = "2026-07-17T22:50:22.719Z" }, + { url = "https://files.pythonhosted.org/packages/62/c0/731b6ddede2e4136912ec4cff2cffbda35af73546be4762c3d7bd3bd79af/websockets-16.1.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:056ae37939ed7e9974f364f5864e76e49182622d8f9751ac1903c0d09b013985", size = 186911, upload-time = "2026-07-17T22:50:24.108Z" }, + { url = "https://files.pythonhosted.org/packages/8c/7f/39c634472c4469a24a7c09cecddffb08fac6d0e74f73881a94ee8a40a196/websockets-16.1.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a0eadbbf2c30f01efa58e1f110eb6fa293261f6b0b1aa38f7f48707107690af9", size = 187204, upload-time = "2026-07-17T22:50:25.548Z" }, + { url = "https://files.pythonhosted.org/packages/26/89/9667c256c256dafcc62d21328ce7a40067da857969b68ee9af375b0aaf72/websockets-16.1.1-cp314-cp314-win32.whl", hash = "sha256:195c978b065fa40910582464f99d6b15c8b314c68e0546549a55ed83f4735328", size = 179603, upload-time = "2026-07-17T22:50:27.086Z" }, + { url = "https://files.pythonhosted.org/packages/bd/dd/1c099d6c0fc5deb6b46ccdbb6981fdb4b12c917869cb3952408409dc18db/websockets-16.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:4e8d01cc3bcae7bbf8167f944aeafefed590fae5693552bba9794a9df68371cc", size = 179948, upload-time = "2026-07-17T22:50:28.521Z" }, + { url = "https://files.pythonhosted.org/packages/35/25/9956b2d5e0529d5d23924f21bba1440d4c5c88a562e4f08550871ffa97a7/websockets-16.1.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:0ffd3031ea8bda8d61762e84220186105ba3b748b3c8da2ae4f7816fac03e573", size = 179963, upload-time = "2026-07-17T22:50:29.982Z" }, + { url = "https://files.pythonhosted.org/packages/17/06/55ffc976c488b6aee9ea05761ff7c4e88e7c1fd82818c8ca7b556ad2f90c/websockets-16.1.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:84a2cef8deffbd9ab8ee0ea546a2a6a7030c28f44e6cdd4547dbfeb489eb8999", size = 177497, upload-time = "2026-07-17T22:50:31.396Z" }, + { url = "https://files.pythonhosted.org/packages/0c/e8/f7dac2e980bacc92bdc26cebae4ae4d50cae5380732c50980598fc0bbae4/websockets-16.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3df13f73af9b3b38ab1195eb299ecb67a4330c911c97ae04043ff74085728abe", size = 177698, upload-time = "2026-07-17T22:50:32.829Z" }, + { url = "https://files.pythonhosted.org/packages/b2/39/26762f734113e22da2b942c3aca85798e0c0405d64c256549540ff31e5a1/websockets-16.1.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:23253dd5bcae3f9aaee0a1d30967a8dbd52e5d3cff93a2e5b84df57b77d4750d", size = 187561, upload-time = "2026-07-17T22:50:34.24Z" }, + { url = "https://files.pythonhosted.org/packages/11/94/c3f330851806b9b02138b774d593478323e73c99238681b4b93efe64e02d/websockets-16.1.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c1c5705e314449e3308872fe084b8571ce078ee4fc55a98a769bdefe5917392", size = 188732, upload-time = "2026-07-17T22:50:36.088Z" }, + { url = "https://files.pythonhosted.org/packages/d1/f2/eb2c450f052de334ae33cf200ece6e87b0e14d186807074e4eb1cd2cdea2/websockets-16.1.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:69e52d175a0a7d1e13b4b67ad41c560b7d98e8c6f6126eb0bda496c784faf8c7", size = 190872, upload-time = "2026-07-17T22:50:38.008Z" }, + { url = "https://files.pythonhosted.org/packages/70/31/2ac8cecf3a74f7fed9132129fc3d90b3998a1554570c11a69b2a8c20332d/websockets-16.1.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1f79c89b5eb034d1722938a891916582f8f7f503f58ca22518a63c3f2cd18499", size = 189305, upload-time = "2026-07-17T22:50:39.53Z" }, + { url = "https://files.pythonhosted.org/packages/6a/cf/8ab19650d3c0d4562c92e70ab47c257c4aa5c6a713ed87fe63766b31fefc/websockets-16.1.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:39f2a024af5c345ffe8fcf1ee18c049c024c94df393bb09b044a6917c77bde43", size = 188033, upload-time = "2026-07-17T22:50:40.912Z" }, + { url = "https://files.pythonhosted.org/packages/66/d7/a49a38a6127a4acb134fb1912b215d900cc657605cff32445bf519f3acc4/websockets-16.1.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:952303a7318d4cbe1011400839bb2051c9f84fa0a35923267f5daba34b15d458", size = 185748, upload-time = "2026-07-17T22:50:42.559Z" }, + { url = "https://files.pythonhosted.org/packages/95/3e/ad1fa40388c7f2e0bb2c7930d0090b6c5498594bd1cdaec18864df3d9e97/websockets-16.1.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:249116b4a76063d930a46391ad56e135c286e4562a18309029fc2c73f4ed4c62", size = 188285, upload-time = "2026-07-17T22:50:43.974Z" }, + { url = "https://files.pythonhosted.org/packages/35/b8/d5db28ca264b9104f82196f92dc8843e35fd391f763d42e4ad358f5bc97e/websockets-16.1.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:61922544a0587a13fd3f53e4c0e5e606510c7b0d9d22c8444e5fae22a06b38cb", size = 186777, upload-time = "2026-07-17T22:50:45.474Z" }, + { url = "https://files.pythonhosted.org/packages/42/9c/726cb39d0cc43ae848dce4aa2acb04eecc6738b1264ec6d700bf6bcfb9f8/websockets-16.1.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:46dcaa042cd1de6c59e7d9269fa63ff7572b6df40510600b678f0826b3c7af51", size = 188682, upload-time = "2026-07-17T22:50:46.973Z" }, + { url = "https://files.pythonhosted.org/packages/be/c7/1168704de8c2dd483edabe4a22cbe4465dd8be8dd95561d214f9fe092871/websockets-16.1.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:38565aca3e01ea8734e578fb2118dade0ecb0250533f29e22b8d1a7a196cf4d0", size = 186377, upload-time = "2026-07-17T22:50:48.413Z" }, + { url = "https://files.pythonhosted.org/packages/ca/40/f9ff2d630ffce4e7dfea0b2288e1caf9ebbf9ff8a9ec9396136ce8b94935/websockets-16.1.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:42f599f4d48c7e1a3338fdaac3acd075be3b3cf02d4b274f3bf2767aedd3d217", size = 187148, upload-time = "2026-07-17T22:50:49.845Z" }, + { url = "https://files.pythonhosted.org/packages/b5/71/e177c8299f78d7cbe2d14df228643c10c70c0e86e108e092056bbcc16e46/websockets-16.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:dcc04fedf83effaeb9cce98abc9469bb1b42ef85f03e01c8c1f4438ef7555737", size = 187578, upload-time = "2026-07-17T22:50:51.619Z" }, + { url = "https://files.pythonhosted.org/packages/49/b2/b6987faf330f5af5c787a2610124c2e8403d51724f9001ec4fff6311fe7a/websockets-16.1.1-cp314-cp314t-win32.whl", hash = "sha256:8483c2096363120eea8b07c06ae7304d520f686665fffd4811fad423930a65d7", size = 179729, upload-time = "2026-07-17T22:50:53.269Z" }, + { url = "https://files.pythonhosted.org/packages/a2/6e/fbac6ed878dd362fbad7d415fa4f84d38e3e33fed8cde45c64e783acf826/websockets-16.1.1-cp314-cp314t-win_amd64.whl", hash = "sha256:bcce07e23e5769375158f5efdcdafa8d5cd014b93c6683865b840ed65b96f231", size = 180072, upload-time = "2026-07-17T22:50:54.969Z" }, + { url = "https://files.pythonhosted.org/packages/e1/ed/71fea6e141590cafc40b14dc5943b0845606bee87bdb52a21b6a73eb4311/websockets-16.1.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:820fb8450edddae3812fd58cbc08e2bf22812cb248ecb5f06dbb82119a56e869", size = 177185, upload-time = "2026-07-17T22:50:56.665Z" }, + { url = "https://files.pythonhosted.org/packages/01/ec/00e7eeca200facf9266a83e4cbbf1bed0e67fba1d4d45031d3e5b3d81b5c/websockets-16.1.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:125f22dbefaf1554fea66fc83851490edb284ce4f501d37ffed2752f418332d9", size = 177459, upload-time = "2026-07-17T22:50:58.197Z" }, + { url = "https://files.pythonhosted.org/packages/75/fd/5774c4b33f7c0d8f0c51809c8b3a93456c48e3543579262cfa64eb5f522e/websockets-16.1.1-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:30bbe120437b5648a77d3519b7024ea09530e0b5b18d3698c5a0ae536fe0cc2e", size = 178294, upload-time = "2026-07-17T22:50:59.641Z" }, + { url = "https://files.pythonhosted.org/packages/37/c3/48e2c03d2bd79bb45948841c592d24156312dd5f58cdf8f549febe652fb6/websockets-16.1.1-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b6b9dadbef0cccd9f4c4ee96b08898afa73e26803bbe0f6aeb5bb12b0074206d", size = 179190, upload-time = "2026-07-17T22:51:01.129Z" }, + { url = "https://files.pythonhosted.org/packages/2d/3f/73e511ecf2496ceac57dd4ed8388efe2bcf0769338a2dbf242c8366ae87e/websockets-16.1.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56cd5fc4f10a9ea8aa0804bddb7b42506cf9e136046f3b4c27de8fec9e2ecba5", size = 180330, upload-time = "2026-07-17T22:51:02.603Z" }, + { url = "https://files.pythonhosted.org/packages/be/4d/2d0d67834092e354d2b0498f014a41249a89556bc406cf86f3e1557bb463/websockets-16.1.1-py3-none-any.whl", hash = "sha256:6abbd3e82c731c8e531714466acd5d87b5e88ac3243465337ba71d68e23ae7e3", size = 173814, upload-time = "2026-07-17T22:51:04.184Z" }, ] [[package]] diff --git a/Configs/.local/lib/hyde/wallpaper.kon.sh b/Configs/.local/lib/hyde/wallpaper.kon.sh index 9bbd70296c..7196c8f817 100755 --- a/Configs/.local/lib/hyde/wallpaper.kon.sh +++ b/Configs/.local/lib/hyde/wallpaper.kon.sh @@ -36,13 +36,13 @@ done if [ ! -z "$setTheme" ] && [ ! -z "$setWall" ]; then inwallHash="$(set_hash "$setWall")" get_hashmap "$tgtPath/$setTheme" - if [[ ${wallHash[@]} == *"$inwallHash"* ]]; then + if [[ ${wallHash[*]} == *"$inwallHash"* ]]; then notify-send -a "HyDE Notify" -i "$thmbDir/$inwallHash.sqre" "Error" "Hash matched in $setTheme" exit 0 fi cp "$setWall" "$tgtPath/$setTheme/wallpapers" ln -fs "$tgtPath/$setTheme/wallpapers/$(basename "$setWall")" "$tgtPath/$setTheme/wall.set" - "$scrDir/themeswitch.sh" -s "$setTheme" + "$scrDir/theme.switch.sh" -s "$setTheme" notify-send -a "HyDE Alert" -i "$thmbDir/$inwallHash.sqre" "Wallpaper set in $setTheme" else echo -e "[Desktop Entry]\nType=Service\nMimeType=image/png;image/jpeg;image/jpg;image/gif\nActions=Menu-Refresh$(printf ";%s" "${thmList[@]}")\nX-KDE-Submenu=Set As Wallpaper...\n\n[Desktop Action Menu-Refresh]\nName=.: Refresh List :.\nExec=$scrName" > "$kmenuDesk" diff --git a/Configs/.local/share/hyde/config-registry.toml b/Configs/.local/share/hyde/config-registry.toml index 468a9658d0..b04dc22d57 100644 --- a/Configs/.local/share/hyde/config-registry.toml +++ b/Configs/.local/share/hyde/config-registry.toml @@ -69,24 +69,9 @@ description = "Hyprland Window Manager" icon = "🪟" [hyprland.files.main] -description = "Main Hyprland Configuration" -path = "${XDG_CONFIG_HOME:-$HOME/.config}/hypr/userprefs.conf" -pre_hook = ["bash", "-c", "echo 'Editing Hyprland main config...'"] - -[hyprland.files.keybinds] -description = "Hyprland Keybindings" -path = "${XDG_CONFIG_HOME:-$HOME/.config}/hypr/keybindings.conf" -pre_hook = ["bash", "-c", "echo 'Editing Hyprland keybinds...'"] - -[hyprland.files.windowrules] -description = "Hyprland Window Rules" -path = "${XDG_CONFIG_HOME:-$HOME/.config}/hypr/windowrules.conf" -pre_hook = ["bash", "-c", "echo 'Editing Hyprland window rules...'"] - -[hyprland.files.nvidia] -description = "Hyprland NVIDIA Settings" -path = "${XDG_CONFIG_HOME:-$HOME/.config}/hypr/nvidia.conf" -pre_hook = ["bash", "-c", "echo 'Editing Hyprland NVIDIA settings...'"] +description = "User Hyprland Configuration - binds, rules and settings" +path = "${XDG_CONFIG_HOME:-$HOME/.config}/hypr/hyprland.lua" +pre_hook = ["bash", "-c", "echo 'Editing Hyprland user config...'"] diff --git a/Configs/.local/share/hyde/schema/config.md b/Configs/.local/share/hyde/schema/config.md index 1aa1a23fdf..fa381f9632 100644 --- a/Configs/.local/share/hyde/schema/config.md +++ b/Configs/.local/share/hyde/schema/config.md @@ -8,7 +8,7 @@ Users are encouraged to use an editor that support schema validation to ensure t --- ### [battery.notify] -batterynotify.sh configuration. +Battery notification configuration. | Key | Description | Default | | --- | ----------- | ------- | @@ -155,7 +155,7 @@ Generic desktop autostart configuration. Use this header instead of hyprland-sta | applet_removable_media | Removable media applet. | hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-removable-media-applet.service -t service -- udiskie --no-automount --smart-tray | | auth_dialogue | Authentication dialogue. | hyde-shell app -t service -- polkitkdeauth.sh | | bar | Bar. | hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-bar.scope -t scope -- waybar.py --watch | -| battery_notify | Battery notification script. | hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-battery-notify.service -t service -- batterynotify.sh | +| battery_notify | Battery notification script. | hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-battery-notify.service -t service -- batterynotify.lua | | blue_light_filter_daemon | Blue-light filter daemon. | hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-blue-light-filter.service -t service -- hyprsunset | | clipboard_persist | Clipboard persist daemon. | hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-clipboard-persist.service -t service wl-clip-persist --clipboard regular | | dbus_share_picker | DBus share picker (for XDG portal / XDPH). | dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP XDG_SESSION_TYPE XDG_SESSION_DESKTOP XDG_CONFIG_HOME QT_QPA_PLATFORMTHEME | diff --git a/Configs/.local/share/hyde/schema/config.toml b/Configs/.local/share/hyde/schema/config.toml index cf3743464e..593d672dde 100644 --- a/Configs/.local/share/hyde/schema/config.toml +++ b/Configs/.local/share/hyde/schema/config.toml @@ -98,7 +98,7 @@ font = "JetBrainsMono Nerd Font" # Font for bookmarks. [wlogout] style = 2 # Style for wlogout. -# batterynotify.sh configuration. +# Battery notification configuration. [battery.notify] timer = 120 # Timer for battery notifications. notify = 1140 # Notification threshold. @@ -215,6 +215,7 @@ steps = 5 # Number of steps to increase/decrease brightness. [sysmonitor] execute = "" # Default command to execute. commands = [""] # Fallback command options. +terminal = "" # Terminal used to launch a console monitor. Falls back to TERMINAL. # hyprlock configuration. [hyprlock] @@ -321,7 +322,7 @@ clipboard_persist = "hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-clipboard-persi wallpaper = "hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-wallpaper.service -t service -- wallpaper.sh --start --global" # Wallpaper script. bar = "hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-bar.scope -t scope -- waybar.py --watch" # Bar. notifications = "hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-notifications.service -t service -- dunst" # Notification daemon. -battery_notify = "hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-battery-notify.service -t service -- batterynotify.sh" # Battery notification script. +battery_notify = "hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-battery-notify.service -t service -- batterynotify.lua" # Battery notification script. applet_network_manager = "hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-network-manager-applet.service -t service -- nm-applet --indicator" # Network manager applet. applet_removable_media = "hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-removable-media-applet.service -t service -- udiskie --no-automount --smart-tray" # Removable media applet. applet_bluetooth = "hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-bluetooth-applet.service -t service -- blueman-applet" # Bluetooth applet. diff --git a/Configs/.local/share/hyde/schema/config.toml.json b/Configs/.local/share/hyde/schema/config.toml.json index ace7cb5899..73701fb369 100644 --- a/Configs/.local/share/hyde/schema/config.toml.json +++ b/Configs/.local/share/hyde/schema/config.toml.json @@ -402,7 +402,7 @@ } }, "battery.notify": { - "description": "batterynotify.sh configuration.", + "description": "Battery notification configuration.", "type": "object", "properties": { "timer": { @@ -1345,7 +1345,7 @@ "type": "string" }, "battery_notify": { - "default": "hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-battery-notify.service -t service -- batterynotify.sh", + "default": "hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-battery-notify.service -t service -- batterynotify.lua", "description": "Battery notification script.", "type": "string" }, diff --git a/Configs/.local/share/hyde/schema/schema.toml b/Configs/.local/share/hyde/schema/schema.toml index 819c7d4cda..d3b981e6a5 100644 --- a/Configs/.local/share/hyde/schema/schema.toml +++ b/Configs/.local/share/hyde/schema/schema.toml @@ -362,7 +362,7 @@ options = [1, 2] type = "integer" [properties."battery.notify"] -description = "batterynotify.sh configuration." +description = "Battery notification configuration." type = "object" [properties."battery.notify".properties.timer] @@ -787,6 +787,11 @@ type = "array" [properties.sysmonitor.properties.commands.items] type = "string" +[properties.sysmonitor.properties.terminal] +default = "" +description = "Terminal used to launch a console monitor. Falls back to TERMINAL." +type = "string" + [properties.hyprlock] description = "hyprlock configuration." type = "object" @@ -1186,7 +1191,7 @@ description = "Notification daemon." type = "string" [properties."desktop.start".properties.battery_notify] -default = "hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-battery-notify.service -t service -- batterynotify.sh" +default = "hyde-shell app -u hyde-$XDG_SESSION_DESKTOP-battery-notify.service -t service -- batterynotify.lua" description = "Battery notification script." type = "string" diff --git a/Configs/.local/share/hypr/lua/dynamic.lua b/Configs/.local/share/hypr/lua/dynamic.lua index 712f106f1e..1a0d0a3014 100644 --- a/Configs/.local/share/hypr/lua/dynamic.lua +++ b/Configs/.local/share/hypr/lua/dynamic.lua @@ -50,18 +50,26 @@ end -- Loads the theme config from lua_state. -- Note this is translated by hyprquery from hyprlang to lua local theme_config = check_require("lua_state.hypr_theme") or {} -if theme_config then - hl.config(theme_config) +if type(theme_config) == "table" then + hl.config(theme_config) end -- Load the HyDE's ui config local state_ui = check_require("lua_state.ui") or {} hyde.config({ui = state_ui.ui or state_ui, wallbash = state_ui.wallbash or {}}, {skip_empty = true}) -- Merge the config safely and ignore blank strings from state UI --- Loads user config if exists -local user_config_path = os.getenv("XDG_CONFIG_HOME") .. "/hyde/config.toml" -if io.open(user_config_path) then - hyde.config.load_toml(user_config_path) +-- Loads the user config if there is one. The directory comes from hyde.path, +-- which leaves it nil rather than building a path out of an unset variable, so +-- a session without XDG_CONFIG_HOME skips the optional file instead of dying +-- on a nil concatenation. The probe closes the handle it opens: this runs on +-- every reload, and a leaked one accumulates for the life of the session. +local user_config_path = hyde.path.config and (hyde.path.config .. "/hyde/config.toml") +if user_config_path then + local user_config = io.open(user_config_path) + if user_config then + user_config:close() + hyde.config.load_toml(user_config_path) + end end check_require("lua_state.animations") diff --git a/Configs/.local/share/hypr/lua/hyde/binds.lua b/Configs/.local/share/hypr/lua/hyde/binds.lua index 4b45d75620..1f925998ae 100644 --- a/Configs/.local/share/hypr/lua/hyde/binds.lua +++ b/Configs/.local/share/hypr/lua/hyde/binds.lua @@ -28,6 +28,48 @@ local function normalize(keycombo) return trim(keycombo:gsub("%s*%+%s*", " + ")) end +-- Modifier spellings Hyprland treats as the same bit. +local modifier_aliases = { + CONTROL = "CTRL", + WIN = "SUPER", + LOGO = "SUPER", + MOD1 = "ALT", + MOD4 = "SUPER" +} + +-- Reduces a combo to the form Hyprland actually matches on: modifiers are a +-- set, so spelling, order and case carry no meaning. "SUPER + CTRL + Left" +-- and "SUPER + CONTROL + LEFT" both become "CTRL + SUPER + LEFT", which is +-- what makes them collide at runtime. +local function canonicalize(keycombo) + local normalized = normalize(keycombo) + if normalized == "" then + return "" + end + + local tokens = {} + for token in normalized:gmatch("[^+]+") do + tokens[#tokens + 1] = trim(token) + end + + local key = table.remove(tokens) or "" + + local modifiers = {} + local seen = {} + for _, token in ipairs(tokens) do + local upper = token:upper() + local modifier = modifier_aliases[upper] or upper + if not seen[modifier] then + seen[modifier] = true + modifiers[#modifiers + 1] = modifier + end + end + table.sort(modifiers) + + modifiers[#modifiers + 1] = key:upper() + return table.concat(modifiers, " + ") +end + local function has_dedup_field(opts) if type(opts) ~= "table" then return false @@ -106,7 +148,11 @@ hyde.binds.dedup_fields = } hyde.binds.normalize = normalize +hyde.binds.canonicalize = canonicalize +-- Maps a canonical combo to the exact string the live bind was registered +-- with. Unbinding matches that string, not the resolved key and modifiers, so +-- the original spelling has to be kept around to remove a bind again. hyde.binds._active = hyde.binds._active or {} local orig_add = hl.bind @@ -115,14 +161,17 @@ hl.bind = function(keycombo, action, ...) local normalized = hyde.binds.normalize(keycombo) local opts = find_options(...) local signature = serialize_flags(opts) - local dedup_id = normalized .. "|" .. signature + local dedup_id = canonicalize(keycombo) .. "|" .. signature - if normalized ~= "" and hyde.binds.dedup and hyde.binds._active[dedup_id] then - hl.unbind(normalized) + if normalized ~= "" and hyde.binds.dedup then + local registered = hyde.binds._active[dedup_id] + if registered then + hl.unbind(registered) + end end if normalized ~= "" then - hyde.binds._active[dedup_id] = true + hyde.binds._active[dedup_id] = normalized keycombo = normalized end diff --git a/Configs/.local/share/hypr/lua/hyde/path.lua b/Configs/.local/share/hypr/lua/hyde/path.lua index b45e7a74c4..fe88e2e8bd 100644 --- a/Configs/.local/share/hypr/lua/hyde/path.lua +++ b/Configs/.local/share/hypr/lua/hyde/path.lua @@ -1,46 +1,120 @@ --- hyde/path.lua --- Provides global access to important XDG and HyDE paths +--- @module hyde.path +--- Resolves the XDG and HyDE directories the Hyprland Lua configuration reads +--- from, and exposes them globally as `hyde.path`. +--- +--- This module is loaded before any other part of the configuration, so it has +--- to survive an environment it does not like. A session started outside uwsm +--- — from a TTY, or through a display manager that exports little — can reach +--- it with `HOME` absent and the XDG variables unset or empty. A field that +--- cannot be resolved is left `nil` for the caller to skip; raising here would +--- take the whole configuration down before Hyprland has a window on screen. +--- +--- Usage: +--- local config_file = hyde.path.config and (hyde.path.config .. "/hyde/config.toml") local P = {} -P.config = os.getenv("XDG_CONFIG_HOME") or (os.getenv("HOME") .. "/.config") -P.cache = os.getenv("XDG_CACHE_HOME") or (os.getenv("HOME") .. "/.cache") -P.state = (os.getenv("XDG_STATE_HOME") or (os.getenv("HOME") .. "/.local/state")) - --- XDG runtime directory -P.runtime = os.getenv("XDG_RUNTIME_DIR") - --- HyDE library directory resolution -local lib_paths = { - os.getenv("HOME") .. "/.local/lib", - "/usr/local/lib", - "/usr/lib", -} -for _, p in ipairs(lib_paths) do - local test = io.popen("[ -d '" .. p .. "' ] && echo 1 || echo 0"):read("*l") - if test == "1" then - P.lib = p - break +local HOME = os.getenv("HOME") + +--- Reads an XDG base directory from the environment. +--- +--- Per the specification a variable that is set but empty counts as unset, and +--- the fallback is derived from `HOME`. +--- +--- @param name string Environment variable holding the directory. +--- @param fallback string|nil Path appended to `HOME` when the variable is +--- unset. Omit it for a directory that has no meaningful default. +--- @return string|nil path The directory, or nil when there is no fallback to +--- derive. +--- +--- Example: +--- env("XDG_CONFIG_HOME", "/.config") --> "/home/user/.config" +--- env("XDG_RUNTIME_DIR") --> nil when the session set nothing +local function env(name, fallback) + local value = os.getenv(name) + if value == nil or value == "" then + return fallback and HOME and HOME .. fallback + end + + return value +end + +--- @field config string|nil User configuration directory. +P.config = env("XDG_CONFIG_HOME", "/.config") + +--- @field cache string|nil User cache directory. +P.cache = env("XDG_CACHE_HOME", "/.cache") + +--- @field state string|nil User state directory. +P.state = env("XDG_STATE_HOME", "/.local/state") + +--- @field data string|nil User data directory. +P.data = env("XDG_DATA_HOME", "/.local/share") + +--- @field runtime string|nil Runtime directory. It has no fallback: the spec +--- requires the session to provide one, and inventing a path would put runtime +--- state somewhere that outlives the session. An empty value is still unset, +--- so it reads as nil rather than as the working directory. +P.runtime = env("XDG_RUNTIME_DIR") + +--- Wraps a value so the shell reads it as one literal word. +--- +--- Single quotes protect everything except a single quote itself, which has to +--- leave the quoted run, contribute an escaped quote and open a new run. Values +--- here are derived from HOME, and a home directory is free to contain one. +--- +--- @param value string Value to pass to the shell. +--- @return string quoted The value as a single quoted shell word. +--- +--- Example: +--- shell_quote("/home/o'brien") --> "'/home/o'\\''brien'" +local function shell_quote(value) + return "'" .. value:gsub("'", "'\\''") .. "'" +end + +--- Reports whether a path is a directory. +--- +--- Plain Lua cannot stat, so this asks the shell. The pipe is closed on every +--- outcome — leaving it open leaks a handle per probe, and this module runs on +--- every configuration reload. +--- +--- @param path string Absolute path to test. +--- @return boolean exists True when the path is a directory. +local function is_directory(path) + local pipe = io.popen("[ -d " .. shell_quote(path) .. " ] && echo 1 || echo 0") + if not pipe then + return false end + + local answer = pipe:read("*l") + pipe:close() + + return answer == "1" end --- HyDE share directory: check user, then system -local share_paths = { - (os.getenv("XDG_DATA_HOME") or (os.getenv("HOME") .. "/.local/share")) .. "", - "/usr/local/share", - "/usr/share", -} -for _, p in ipairs(share_paths) do - local test = io.popen("[ -d '" .. p .. "' ] && echo 1 || echo 0"):read("*l") - if test == "1" then - P.share = p - break +--- Returns the first candidate that exists, preferring the user's own. +--- +--- @param user_path string|nil User candidate, nil when it cannot be resolved. +--- @param system_paths table Ordered system candidates to fall back on. +--- @return string|nil path The first existing directory, or nil when none do. +local function first_directory(user_path, system_paths) + if user_path and is_directory(user_path) then + return user_path + end + + for _, path in ipairs(system_paths) do + if is_directory(path) then + return path + end end end +--- @field lib string|nil Directory holding the HyDE Lua and shell libraries. +P.lib = first_directory(HOME and HOME .. "/.local/lib", {"/usr/local/lib", "/usr/lib"}) +--- @field share string|nil Directory holding the shipped HyDE data files. +P.share = first_directory(P.data, {"/usr/local/share", "/usr/share"}) --- Make globally accessible _G.hyde = _G.hyde or {} _G.hyde.path = P diff --git a/Configs/.local/share/hypr/lua/key_binds.lua b/Configs/.local/share/hypr/lua/key_binds.lua index 3a2193d8cb..f5eb8d2e24 100644 --- a/Configs/.local/share/hypr/lua/key_binds.lua +++ b/Configs/.local/share/hypr/lua/key_binds.lua @@ -1,3 +1,11 @@ +-- * Enable bind deduplication so repeated key combos don't conflict. +-- * This has to run before the first bind below, otherwise the binds in this +-- * file are registered unchecked and only user overrides get deduplicated. +-- * For multiple dispatcher actions, wrap them in one function and bind that. +-- * If you set `hyde.binds.dedup = false`, unbind duplicates manually. +hyde.binds.dedup = true +-- hyde.binds.dedup_fields = {} + -- vars for easy access local _apps = hyde.config.app local MOD = hyde.config.modifiers.main @@ -42,7 +50,7 @@ end _F = {description = "[Launcher|Apps] terminal emulator"} hl.bind(MOD .. " + T", hl.dsp.exec_cmd(_apps.terminal), _F) _F = {description = "[Launcher|Apps] dropdown terminal"} -hl.bind(MOD .. " + grave", hl.dsp.exec_cmd("hyde-shell pypr toggle console"), _F) +hl.bind(MOD .. " + ALT + T", hl.dsp.exec_cmd("hyde-shell pypr toggle console"), _F) _F = {description = "[Launcher|Apps] file explorer"} hl.bind(MOD .. " + E", hl.dsp.exec_cmd(_apps.explorer), _F) _F = {description = "[Launcher|Apps] browser"} @@ -55,10 +63,12 @@ hl.bind("CTRL + SHIFT + ESCAPE", hl.dsp.exec_cmd("hyde-shell system.monitor.sh") local _wm = "Window Management" _F = {description = "[Window Management] close focused window"} hl.bind(MOD .. " + Q", hl.dsp.window.close(), _F) +_F = {description = "[Window Management] close focused window"} +hl.bind("ALT + F4", hl.dsp.window.close(), _F) _F = {description = "[Window Management] kill focused window"} hl.bind(MOD .. "+ ALT + F4", hl.dsp.window.kill(), _F) _F = {description = "[Window Management] exit hyprland session"} -hl.bind("CTRL + Delete", hl.dsp.exit(), _F) +hl.bind(MOD .. " + Delete", hl.dsp.exit(), _F) _F = {description = "[Window Management] toggle float true"} hl.bind(MOD .. " + W", hl.dsp.window.float({action = "toggle"}), _F) _F = {description = "[Window Management] toggle group"} @@ -68,24 +78,22 @@ hl.bind("ALT + P", hl.dsp.window.pseudo(), _F) -- bindd = $mainMod, G, $d toggle group,exec, hydectl tabs _F = {description = "[Window Management] cycle fullscreen"} -hl.bind(MOD .. " + F11", cycle_fullscreen, _F) +hl.bind("SHIFT + F11", cycle_fullscreen, _F) _F = {description = "[Window Management] toggle pin"} -hl.bind(MOD .. " + F", hl.dsp.exec_cmd(hyde.sh.window.pin()), _F) +hl.bind(MOD .. " + SHIFT + F", hl.dsp.exec_cmd(hyde.sh.window.pin()), _F) _F = {description = "[Window Management] logout menu"} hl.bind("CTRL + ALT + DELETE", hl.dsp.exec_cmd(hyde.sh.session.logout.launcher()), _F) +-- ALT_R is a keysym, not a modifier: "ALT_R + CONTROL_R" resolves to a bare +-- right Control, so every press of that key hid the bar. _F = {description = "[Window Management] hide waybar"} -hl.bind("ALT_R + CONTROL_R", hl.dsp.exec_cmd(hyde.sh.waybar("--hide")), _F) +hl.bind(MOD .. " + CTRL + B", hl.dsp.exec_cmd(hyde.sh.waybar("--hide")), _F) _F = {description = "[Window Management] lock session"} hl.bind(MOD .. " + L", hl.dsp.exec_cmd(hyde.sh.session.lock()), _F) _F = {description = "[Window Management|Group Navigation] change active group backwards"} -hl.bind(MOD .. " + CTRL + Left", hl.dsp.group.prev(), _F) -_F = {description = "[Window Management|Group Navigation] change active group forwards"} -hl.bind(MOD .. " + CTRL + Right", hl.dsp.group.next(), _F) -_F = {description = "[Window Management|Group Navigation] change active group backwards"} -hl.bind(MOD .. " + ALT + Left", hl.dsp.group.prev(), _F) +hl.bind(MOD .. " + CTRL + H", hl.dsp.group.prev(), _F) _F = {description = "[Window Management|Group Navigation] change active group forwards"} -hl.bind(MOD .. " + ALT + Right", hl.dsp.group.next(), _F) +hl.bind(MOD .. " + CTRL + L", hl.dsp.group.next(), _F) -- $d=[$wm|Change focus] @@ -114,15 +122,15 @@ hl.bind("ALT + ALT_L", hl.dsp.exec_cmd(hyde.sh.altab("--apply")), _F) -- # Resize kwindows _F = {description = "[Window Management|Resize Active Window] resize window right", repeating = true} -hl.bind(MOD .. " + EQUAL", hl.dsp.window.resize({x = 30, y = 0, relative = true}), _F) +hl.bind(MOD .. " + SHIFT + RIGHT", hl.dsp.window.resize({x = 30, y = 0, relative = true}), _F) _F = {description = "[Window Management|Resize Active Window] resize window left", repeating = true} -hl.bind(MOD .. " + MINUS", hl.dsp.window.resize({x = -30, y = 0, relative = true}), _F) +hl.bind(MOD .. " + SHIFT + LEFT", hl.dsp.window.resize({x = -30, y = 0, relative = true}), _F) _F = {description = "[Window Management|Resize Active Window] resize window up", repeating = true} -hl.bind(MOD .. " + SHIFT + EQUAL", hl.dsp.window.resize({x = 0, y = -30, relative = true}), _F) +hl.bind(MOD .. " + SHIFT + UP", hl.dsp.window.resize({x = 0, y = -30, relative = true}), _F) _F = {description = "[Window Management|Resize Active Window] resize window down", repeating = true} -hl.bind(MOD .. " + SHIFT + MINUS", hl.dsp.window.resize({x = 0, y = 30, relative = true}), _F) +hl.bind(MOD .. " + SHIFT + DOWN", hl.dsp.window.resize({x = 0, y = 30, relative = true}), _F) -- TEXT = hl.get_active_window().floating @@ -150,7 +158,7 @@ hl.bind(MOD .. " + X", hl.dsp.window.resize(), _F) -- $d=[$wm] _F = {description = "[Layout Management|Dwindle] toggle split"} -_F = {description = "[Layout Management|Scrolling] toggle fit"} +hl.bind(MOD .. " + J", hl.dsp.layout("togglesplit"), _F) _F = {description = "[Launcher|Rofi menus] application finder"} hl.bind(MOD .. " + A", hl.dsp.exec_cmd(hyde.sh.menu.apps()), _F) @@ -182,6 +190,12 @@ hl.bind(MOD .. " + SHIFT + slash", hl.dsp.exec_cmd(hyde.sh.menu.search()), _F) -- # binddel = , F11, $d decrease volume , exec, hyde-shell volumecontrol.sh -o d # decrease volume -- # binddel = , F12, $d increase volume , exec, hyde-shell volumecontrol.sh -o i # increase volume +_F = {description = "[Hardware Controls|Audio] un/mute output", locked = true} +hl.bind("F10", hl.dsp.exec_cmd(hyde.sh.volumecontrol("-o", "m")), _F) +_F = {description = "[Hardware Controls|Audio] decrease volume", locked = true, repeating = true} +hl.bind("F11", hl.dsp.exec_cmd(hyde.sh.volumecontrol("-o", "d")), _F) +_F = {description = "[Hardware Controls|Audio] increase volume", locked = true, repeating = true} +hl.bind("F12", hl.dsp.exec_cmd(hyde.sh.volumecontrol("-o", "i")), _F) _F = {description = "[Hardware Controls|Audio] un/mmute output", locked = true} hl.bind("XF86AudioMute", hl.dsp.exec_cmd(hyde.sh.volumecontrol("-o", "m")), _F) _F = {description = "[Hardware Controls|Audio] un/mute microphone", locked = true} @@ -211,26 +225,30 @@ _F = {description = "[Utilities] toggle keyboard layout", locked = true} hl.bind(MOD .. " + K", hl.dsp.exec_cmd(hyde.sh.kb.switch()), _F) _F = {description = "[Utilities] game mode", locked = true} hl.bind(MOD .. " + ALT + G", hl.dsp.exec_cmd(hyde.sh.gamemode()), _F) -- TODO +_F = {description = "[Utilities] game launcher"} +hl.bind(MOD .. " + SHIFT + G", hl.dsp.exec_cmd("hyde-shell gamelauncher"), _F) _F = {description = "[Utilities] screen capture] color picker", locked = true} hl.bind(MOD .. " + SHIFT + P", hl.dsp.exec_cmd("hyprpicker -an"), _F) _F = {description = "[Utilities] partial screenshot capture", locked = true} -hl.bind(MOD .. " + S", hl.dsp.exec_cmd(hyde.sh.screenshot.snip()), _F) +hl.bind(MOD .. " + P", hl.dsp.exec_cmd(hyde.sh.screenshot.snip()), _F) _F = {description = "[Utilities] freeze and snip screen", locked = true} -hl.bind(MOD .. " + SHIFT + S", hl.dsp.exec_cmd(hyde.sh.screenshot.freeze()), _F) +hl.bind(MOD .. " + CONTROL + P", hl.dsp.exec_cmd(hyde.sh.screenshot.freeze()), _F) _F = {description = "[Utilities] print monitor", locked = true} -hl.bind(MOD .. " + ALT + S", hl.dsp.exec_cmd(hyde.sh.screenshot.monitor()), _F) +hl.bind(MOD .. " + ALT + P", hl.dsp.exec_cmd(hyde.sh.screenshot.monitor()), _F) _F = {description = "[Utilities] print all monitors", locked = true} -hl.bind(MOD .. " + CONTROL + A", hl.dsp.exec_cmd(hyde.sh.screenshot.monitor()), _F) +hl.bind("Print", hl.dsp.exec_cmd(hyde.sh.screenshot.full()), _F) _F = {description = "[Utilities] OCR scanner", locked = true} hl.bind(MOD .. " + CONTROL + S", hl.dsp.exec_cmd(hyde.sh.screenshot.ocr()), _F) --- _F = { description = "[Theming and Wallpaper] next global wallpaper"} --- hl.bind(MOD .. "+ ALT + Right", hl.dsp.exec_cmd(hyde.sh.wallpaper("--next")), _F) --- _F = { description = "[Theming and Wallpaper] previous global wallpaper"} --- hl.bind(MOD .. "+ ALT + Left", hl.dsp.exec_cmd(hyde.sh.wallpaper("--prev")), _F) --- _F = { description = "[Theming and Wallpaper] next waybar layout"} --- hl.bind(MOD .. "+ CONTROL + ALT + Right", hl.dsp.exec_cmd(hyde.sh.waybar("--next")), _F) +_F = {description = "[Theming and Wallpaper] next global wallpaper"} +hl.bind(MOD .. "+ ALT + Right", hl.dsp.exec_cmd(hyde.sh.wallpaper("--next")), _F) +_F = {description = "[Theming and Wallpaper] previous global wallpaper"} +hl.bind(MOD .. "+ ALT + Left", hl.dsp.exec_cmd(hyde.sh.wallpaper("--prev")), _F) +_F = {description = "[Theming and Wallpaper] next Waybar layout"} +hl.bind(MOD .. "+ ALT + Up", hl.dsp.exec_cmd("hyde-shell waybar --next"), _F) +_F = {description = "[Theming and Wallpaper] previous Waybar layout"} +hl.bind(MOD .. "+ ALT + Down", hl.dsp.exec_cmd("hyde-shell waybar --prev"), _F) _F = {description = "[Theming and Wallpaper] select a global wallpaper"} hl.bind(MOD .. "+ SHIFT + W", hl.dsp.exec_cmd(hyde.sh.menu.wallpapers()), _F) @@ -238,6 +256,10 @@ _F = {description = "[Theming and Wallpaper] wallbash mode selector"} hl.bind(MOD .. "+ SHIFT + R", hl.dsp.exec_cmd(hyde.sh.menu.wallbash()), _F) _F = {description = "[Theming and Wallpaper] select a theme"} hl.bind(MOD .. "+ SHIFT + T", hl.dsp.exec_cmd(hyde.sh.menu.themes()), _F) +_F = {description = "[Theming and Wallpaper] select animations"} +hl.bind(MOD .. "+ SHIFT + Y", hl.dsp.exec_cmd("hyde-shell animations --select"), _F) +_F = {description = "[Theming and Wallpaper] select Hyprlock layout"} +hl.bind(MOD .. "+ SHIFT + U", hl.dsp.exec_cmd("hyde-shell hyprlock --select"), _F) -- # TODO Make a main rofi menu for these selectors -- $rice=Theming and Wallpaper @@ -250,17 +272,20 @@ hl.bind(MOD .. "+ SHIFT + T", hl.dsp.exec_cmd(hyde.sh.menu.themes()), _F) -- bindd = $mainMod SHIFT, R, $d wallbash mode selector , exec, pkill -x rofi || hyde-shell wallbashtoggle.sh -m # launch wallbash mode select menu -- bindd = $mainMod SHIFT, T, $d select a theme, exec, pkill -x rofi || hyde-shell themeselect.sh # launch theme select menu +-- Numpad keys for workspaces 11-20. The Lua bind parser has no keycode form, +-- so each key is bound under both keysyms it can emit: the digit while Num +-- Lock is on, the navigation name while it is off. local kp = { - [1] = 87, - [2] = 88, - [3] = 89, - [4] = 83, - [5] = 84, - [6] = 85, - [7] = 79, - [8] = 80, - [9] = 81, - [0] = 90 + [1] = {"KP_1", "KP_End"}, + [2] = {"KP_2", "KP_Down"}, + [3] = {"KP_3", "KP_Next"}, + [4] = {"KP_4", "KP_Left"}, + [5] = {"KP_5", "KP_Begin"}, + [6] = {"KP_6", "KP_Right"}, + [7] = {"KP_7", "KP_Home"}, + [8] = {"KP_8", "KP_Up"}, + [9] = {"KP_9", "KP_Prior"}, + [10] = {"KP_0", "KP_Insert"} } for i = 1, 10 do @@ -269,8 +294,13 @@ for i = 1, 10 do end for i = 1, 10 do - local key = (i == 10) and 90 or kp[i] - hl.bind(MOD .. "+code:" .. key, hl.dsp.focus({workspace = tostring(i + 10)}), {description = "WS " .. (i + 10)}) + for _, key in ipairs(kp[i]) do + hl.bind( + MOD .. " + " .. key, + hl.dsp.focus({workspace = tostring(i + 10)}), + {description = "[Workspaces|Navigation] navigate to workspace " .. (i + 10)} + ) + end end _F = {description = "[Workspaces|Navigation|Relative workspace] change active workspace forwards"} @@ -287,12 +317,13 @@ for i = 1, 10 do end for i = 1, 10 do - local key = (i == 10) and 90 or kp[i] - hl.bind( - MOD .. "+SHIFT+code:" .. key, - hl.dsp.window.move({workspace = tostring(i + 10)}), - {description = "WS " .. (i + 10)} - ) + for _, key in ipairs(kp[i]) do + hl.bind( + MOD .. " + SHIFT + " .. key, + hl.dsp.window.move({workspace = tostring(i + 10)}), + {description = "[Workspaces|Move window to workspace] move focused window to workspace " .. (i + 10)} + ) + end end _F = {description = "[Workspaces|Move window to workspace|Relative workspace] move focused window to next workspace"} @@ -303,15 +334,17 @@ _F = { hl.bind(MOD .. " + CONTROL + ALT + LEFT", hl.dsp.window.move({workspace = "r-1"}), _F) _F = {description = "[Workspaces|Navigation|Mouse] next workspace"} -hl.bind(MOD .. " + SHIFT + mouse_down", hl.dsp.focus({workspace = "r+1"}), _F) +hl.bind(MOD .. " + mouse_down", hl.dsp.focus({workspace = "e+1"}), _F) _F = {description = "[Workspaces|Navigation|Mouse] previous workspace"} -hl.bind(MOD .. " + SHIFT + mouse_up", hl.dsp.focus({workspace = "r-1"}), _F) +hl.bind(MOD .. " + mouse_up", hl.dsp.focus({workspace = "e-1"}), _F) -- # Move/Switch to special workspace (scratchpad) --- $d=[$ws|Navigation|Special workspace] --- # bindd = $mainMod, grave, $d toggle scratchpad , togglespecialworkspace --- # bindd = $mainMod SHIFT, grave, $d move to scratchpad , movetoworkspace, special --- # bindd = $mainMod Alt, grave, $d move to scratchpad (silent) , movetoworkspacesilent, special +_F = {description = "[Workspaces|Navigation|Special workspace] toggle scratchpad"} +hl.bind(MOD .. " + S", hl.dsp.workspace.toggle_special(), _F) +_F = {description = "[Workspaces|Navigation|Special workspace] move focused window to scratchpad"} +hl.bind(MOD .. " + SHIFT + S", hl.dsp.window.move({workspace = "special"}), _F) +_F = {description = "[Workspaces|Navigation|Special workspace] move focused window silently to scratchpad"} +hl.bind(MOD .. " + ALT + S", hl.dsp.window.move({workspace = "special", follow = false}), _F) --- Move silent --- @@ -372,9 +405,3 @@ end -- bindk = Super ALT, F ,test device, exec , notify-send "Hyprland" "You just pressed Super + F again!2" -- # bindd = Alt, D , [Utilities] Enable Wayscriber ,exec, wayscriber --active - --- * Enable bind deduplication so repeated key combos don't conflict. --- * For multiple dispatcher actions, wrap them in one function and bind that. --- * If you set `hyde.bind.dedup = false`, unbind duplicates manually. -hyde.binds.dedup = true --- hyde.binds.dedup_fields = {} diff --git a/Configs/.local/share/waybar/layouts/macos.jsonc b/Configs/.local/share/waybar/layouts/macos.jsonc index ac6c60223a..5bdf0d1cc6 100644 --- a/Configs/.local/share/waybar/layouts/macos.jsonc +++ b/Configs/.local/share/waybar/layouts/macos.jsonc @@ -94,8 +94,8 @@ "wallpaper-next": "hyde-shell wallpaper --next --global", "wallpaper-previous": "hyde-shell wallpaper --previous --global", "wallpaper-random": "hyde-shell wallpaper --random --global", - "theme-next": "hyde-shell themeswitch -n", - "theme-previous": "hyde-shell themeswitch -p", + "theme-next": "hyde-shell theme.switch -n", + "theme-previous": "hyde-shell theme.switch -p", "theme-select": "hyde-shell themeselect", "theme-import": "hyde-shell app -T -- hydectl theme import", "waybar-restart": "hyde-shell waybar -ubg", diff --git a/Configs/.local/share/waybar/modules/custom-hyde-menu.jsonc b/Configs/.local/share/waybar/modules/custom-hyde-menu.jsonc index 993c416ea9..11d9a2c8a9 100644 --- a/Configs/.local/share/waybar/modules/custom-hyde-menu.jsonc +++ b/Configs/.local/share/waybar/modules/custom-hyde-menu.jsonc @@ -11,8 +11,8 @@ "wallpaper-next": "hyde-shell wallpaper --next --global", "wallpaper-previous": "hyde-shell wallpaper --previous --global", "wallpaper-random": "hyde-shell wallpaper --random --global", - "theme-next": "hyde-shell themeswitch -n", - "theme-previous": "hyde-shell themeswitch -p", + "theme-next": "hyde-shell theme.switch -n", + "theme-previous": "hyde-shell theme.switch -p", "theme-select": "hyde-shell themeselect", "theme-import": "hyde-shell app -T -- hydectl theme import", "layouts-select": "hyde-shell layouts --select;pkill -RTMIN+19 waybar", diff --git a/Configs/.local/share/waybar/modules/custom-theme.jsonc b/Configs/.local/share/waybar/modules/custom-theme.jsonc index 0b4e0992a2..162cd34de2 100644 --- a/Configs/.local/share/waybar/modules/custom-theme.jsonc +++ b/Configs/.local/share/waybar/modules/custom-theme.jsonc @@ -3,8 +3,8 @@ "format": "{0}", "rotate": 0, "tooltip-format": "\udb81\udfe1 Switch theme", - "on-click": "hyde-shell themeswitch -n", - "on-click-right": "hyde-shell themeswitch -p", + "on-click": "hyde-shell theme.switch -n", + "on-click-right": "hyde-shell theme.switch -p", "on-click-middle": "sleep 0.1 && hyde-shell themeselect", "interval": 86400, "tooltip": true diff --git a/Configs/.local/share/waybar/modules/hyprland-workspaces#kanji.jsonc b/Configs/.local/share/waybar/modules/hyprland-workspaces#kanji.jsonc index de2284cdac..150c3d0c97 100644 --- a/Configs/.local/share/waybar/modules/hyprland-workspaces#kanji.jsonc +++ b/Configs/.local/share/waybar/modules/hyprland-workspaces#kanji.jsonc @@ -4,10 +4,10 @@ "class": "no-margin-padding", "all-outputs": true, "active-only": false, - "on-click": "activate", "disable-scroll": false, - "on-scroll-up": "hyprctl dispatch workspace -1", - "on-scroll-down": "hyprctl dispatch workspace +1", + "tooltip": false, + "on-scroll-up": "hyprctl dispatch 'hl.dsp.focus({workspace=\"e-1\"})'", + "on-scroll-down": "hyprctl dispatch 'hl.dsp.focus({workspace=\"e+1\"})'", "persistent-workspaces": {}, "format": "{icon}", "format-icons": { diff --git a/Configs/.local/share/waybar/modules/hyprland-workspaces#roman.jsonc b/Configs/.local/share/waybar/modules/hyprland-workspaces#roman.jsonc index 7123159118..cd5078e02e 100644 --- a/Configs/.local/share/waybar/modules/hyprland-workspaces#roman.jsonc +++ b/Configs/.local/share/waybar/modules/hyprland-workspaces#roman.jsonc @@ -4,10 +4,10 @@ "class": "no-margin-padding", "all-outputs": true, "active-only": false, - "on-click": "activate", "disable-scroll": false, - "on-scroll-up": "hyprctl dispatch workspace -1", - "on-scroll-down": "hyprctl dispatch workspace +1", + "tooltip": false, + "on-scroll-up": "hyprctl dispatch 'hl.dsp.focus({workspace=\"e-1\"})'", + "on-scroll-down": "hyprctl dispatch 'hl.dsp.focus({workspace=\"e+1\"})'", "persistent-workspaces": {}, "format": "{icon}", "format-icons": { diff --git a/Configs/.local/share/waybar/modules/hyprland-workspaces.jsonc b/Configs/.local/share/waybar/modules/hyprland-workspaces.jsonc index 20d5c08900..b15a8ef2fb 100644 --- a/Configs/.local/share/waybar/modules/hyprland-workspaces.jsonc +++ b/Configs/.local/share/waybar/modules/hyprland-workspaces.jsonc @@ -2,10 +2,10 @@ "hyprland/workspaces": { "all-outputs": true, "active-only": false, - "on-click": "activate", "disable-scroll": false, - "on-scroll-up": "hyprctl dispatch workspace -1", - "on-scroll-down": "hyprctl dispatch workspace +1", + "tooltip": false, + "on-scroll-up": "hyprctl dispatch 'hl.dsp.focus({workspace=\"e-1\"})'", + "on-scroll-down": "hyprctl dispatch 'hl.dsp.focus({workspace=\"e+1\"})'", "persistent-workspaces": {} } } diff --git a/Hyprdots-to-HyDE.md b/Hyprdots-to-HyDE.md index c053581d5f..acdae9a299 100644 --- a/Hyprdots-to-HyDE.md +++ b/Hyprdots-to-HyDE.md @@ -67,9 +67,14 @@ Who are the $USER? --- -Here's how we can update HyDE-specific Hyprland settings without changing user preferences. We don't need the "userprefs" file. Instead, we can source HyDE's `hyprland.conf` and make $USER preferred changes directly in the config. With this approach, you won't potentially break hyde and hyde won't break your own dots. - - +Here's how we keep HyDE's Hyprland settings separate from yours. HyDE's own +configuration lives in `~/.local/share/hypr/`, which it overwrites on every +update, and yours goes in `~/.config/hypr/hyprland.lua`, which loads after it +and is never touched. Anything else HyDE puts in `~/.config/hypr/` — the lock +screen, idle and sunset configs — is left alone once it exists. So an update +cannot overwrite your settings, and your settings cannot be lost with one. +Your own file is still yours to get wrong: a Lua error in it will stop the +session from starting, and a HyDE change may need a matching change there. # Why name it HyDE? diff --git a/KEYBINDINGS.md b/KEYBINDINGS.md index f41e7db24a..a1f245aab0 100644 --- a/KEYBINDINGS.md +++ b/KEYBINDINGS.md @@ -20,6 +20,7 @@ Multi-language KEYBINDINGS support [](Source/assets/keybinds/KEYBINDINGS.zh.md) [](Source/assets/keybinds/KEYBINDINGS.fr.md) [](Source/assets/keybinds/KEYBINDINGS.ar.md) +[](Source/assets/keybinds/KEYBINDINGS.pt-br.md)