Compare commits
97 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
b0e9d60ff7
|
|||
|
95076ff6ab
|
|||
|
f26ab854c9
|
|||
|
6e84d0c48b
|
|||
|
1b0e46d33a
|
|||
|
ae6519687a
|
|||
|
0caab02933
|
|||
|
074b378f03
|
|||
|
6a5533f783
|
|||
|
bb48e185d0
|
|||
|
83128dc7bb
|
|||
|
780e9c35bf
|
|||
|
3aaf9de5f2
|
|||
|
a1c7d2c983
|
|||
|
63d54df66a
|
|||
|
959fb15828
|
|||
|
36037cb3e5
|
|||
|
800a4e354c
|
|||
|
9f1ef95f46
|
|||
|
064102b786
|
|||
|
621f76c797
|
|||
|
2d1df86a46
|
|||
|
6ba94ba664
|
|||
|
f1170bc161
|
|||
|
dbb47ec2ee
|
|||
|
c413f6d4b2
|
|||
|
8ce60cdd2f
|
|||
|
d9af9c1057
|
|||
|
e816ddb32a
|
|||
|
57e2163bac
|
|||
|
60e40f4fe2
|
|||
|
7c76e60656
|
|||
|
6fe5f7de4c
|
|||
|
8e2e7be56f
|
|||
|
3275cd1fa2
|
|||
|
087091577c
|
|||
|
f6a41d7c51
|
|||
|
7538dfad2d
|
|||
|
2d8867f6fa
|
|||
|
4f5d4cb64b
|
|||
|
1704f90934
|
|||
|
41be32692c
|
|||
|
65a98dfd7c
|
|||
|
ce848bff0f
|
|||
|
6859e9abc9
|
|||
|
82f19cc144
|
|||
|
e4ce659174
|
|||
|
8f3df19786
|
|||
|
f8ecf7d0f7
|
|||
|
5b8335654f
|
|||
|
2a0ce32bdd
|
|||
|
13e1b220ff
|
|||
|
8827d1d473
|
|||
|
70fa559752
|
|||
|
bcfbd40003
|
|||
|
38188632e0
|
|||
|
682f3de097
|
|||
|
5295733629
|
|||
|
49e76b49de
|
|||
|
60a14b6683
|
|||
|
d2a3719b78
|
|||
|
d453b64d3f
|
|||
|
09c3980c50
|
|||
|
ed6ad5981a
|
|||
|
6c749be5f7
|
|||
|
8f21138f26
|
|||
|
542f2bca6b
|
|||
|
b9097f40f6
|
|||
|
4102e3c02c
|
|||
|
474a5973a3
|
|||
|
a65389ec62
|
|||
|
0c256943fd
|
|||
|
da2c8de56f
|
|||
|
eb02e8eee6
|
|||
|
24c8108f35
|
|||
|
67d044a426
|
|||
|
e52501a1df
|
|||
|
f57e8c59d6
|
|||
|
5ba2c825a1
|
|||
|
d11bd2c54e
|
|||
|
c68e1f9d49
|
|||
|
253bfb530b
|
|||
|
6c38c3a526
|
|||
|
45b1b16c77
|
|||
|
2728f9d1eb
|
|||
|
77aaf87860
|
|||
|
57261fb13a
|
|||
|
5c41eab9d7
|
|||
|
99c95edd57
|
|||
|
7d90142f0f
|
|||
|
71e1a744c5
|
|||
|
80af5c22d6
|
|||
|
7ba17a0161
|
|||
|
4cf8c394b9
|
|||
|
e225306419
|
|||
|
858734384b
|
|||
|
278a7f95a9
|
@@ -2,6 +2,7 @@
|
||||
/build
|
||||
|
||||
# Qt Creator files
|
||||
/.qtcreator
|
||||
/CMakeLists.txt.user*
|
||||
/xK.config
|
||||
/xK.files
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
[submodule "liberty"]
|
||||
path = liberty
|
||||
url = https://git.janouch.name/p/liberty.git
|
||||
[submodule "termo"]
|
||||
path = termo
|
||||
url = https://git.janouch.name/p/termo.git
|
||||
|
||||
+118
-42
@@ -8,11 +8,6 @@ string (STRIP "${project_version}" project_version)
|
||||
project (xK VERSION "${project_version}"
|
||||
DESCRIPTION "IRC daemon, bot, TUI client and its web frontend" LANGUAGES C)
|
||||
|
||||
# Options
|
||||
option (WANT_READLINE "Use GNU Readline for the UI (better)" ON)
|
||||
option (WANT_LIBEDIT "Use BSD libedit for the UI" OFF)
|
||||
option (WANT_XF "Build xF" OFF)
|
||||
|
||||
# Moar warnings
|
||||
set (CMAKE_C_STANDARD 99)
|
||||
set (CMAKE_C_STANDARD_REQUIRED ON)
|
||||
@@ -72,6 +67,8 @@ endif ()
|
||||
# -lrt is only for glibc < 2.17
|
||||
# -liconv may or may not be a part of libc
|
||||
# -lm may or may not be a part of libc
|
||||
find_path (iconv_INCLUDE_DIRS iconv.h)
|
||||
include_directories (${iconv_INCLUDE_DIRS})
|
||||
foreach (extra iconv rt m)
|
||||
find_library (extra_lib_${extra} ${extra})
|
||||
if (extra_lib_${extra})
|
||||
@@ -88,13 +85,32 @@ CHECK_C_SOURCE_RUNS ("#include <iconv.h>
|
||||
== (iconv_t) -1; }" ICONV_ACCEPTS_TRANSLIT)
|
||||
|
||||
# Dependencies for xC
|
||||
pkg_check_modules (libffi REQUIRED libffi)
|
||||
list (APPEND xC_libraries ${libffi_LIBRARIES})
|
||||
include_directories (${libffi_INCLUDE_DIRS})
|
||||
link_directories (${libffi_LIBRARY_DIRS})
|
||||
find_package (Termo QUIET NO_MODULE)
|
||||
option (USE_SYSTEM_TERMO
|
||||
"Don't compile our own termo library, use the system one" "${Termo_FOUND}")
|
||||
if (USE_SYSTEM_TERMO)
|
||||
if (NOT Termo_FOUND)
|
||||
message (FATAL_ERROR "System termo library not found")
|
||||
endif ()
|
||||
else ()
|
||||
# We don't want the library to install, but EXCLUDE_FROM_ALL ignores tests
|
||||
add_subdirectory (termo EXCLUDE_FROM_ALL)
|
||||
file (WRITE ${PROJECT_BINARY_DIR}/CTestCustom.cmake
|
||||
"execute_process (COMMAND ${CMAKE_COMMAND} --build termo)")
|
||||
|
||||
# We don't have many good choices; this is a relatively clean approach
|
||||
# (other possibilities: setting a variable in the parent scope, using
|
||||
# a cache variable, writing a special config file with build paths in it
|
||||
# and including it here, or setting a custom property on the targets)
|
||||
get_directory_property (Termo_INCLUDE_DIRS
|
||||
DIRECTORY termo INCLUDE_DIRECTORIES)
|
||||
set (Termo_LIBRARIES termo-static)
|
||||
endif ()
|
||||
list (APPEND xC_libraries ${Termo_LIBRARIES})
|
||||
|
||||
# XXX: other Lua versions may be acceptable, don't know yet
|
||||
pkg_search_module (lua lua53 lua5.3 lua-5.3 lua54 lua5.4 lua-5.4 lua>=5.3)
|
||||
pkg_search_module (lua
|
||||
lua53 lua5.3 lua-5.3 lua54 lua5.4 lua-5.4 lua55 lua5.5 lua-5.5 lua>=5.3)
|
||||
option (WITH_LUA "Enable support for Lua plugins" ${lua_FOUND})
|
||||
|
||||
if (WITH_LUA)
|
||||
@@ -119,32 +135,45 @@ else ()
|
||||
message (SEND_ERROR "Curses not found")
|
||||
endif ()
|
||||
|
||||
if ((WANT_READLINE AND WANT_LIBEDIT) OR (NOT WANT_READLINE AND NOT WANT_LIBEDIT))
|
||||
message (SEND_ERROR "You have to choose either GNU Readline or libedit")
|
||||
elseif (WANT_READLINE)
|
||||
pkg_check_modules (readline readline)
|
||||
# Dependencies for xF
|
||||
find_package (Unistring)
|
||||
|
||||
# OpenBSD's default readline is too old
|
||||
if ("${CMAKE_SYSTEM_NAME}" MATCHES "OpenBSD")
|
||||
include_directories (${OPENBSD_LOCALBASE}/include/ereadline)
|
||||
list (APPEND xC_libraries ereadline)
|
||||
elseif (readline_FOUND)
|
||||
list (APPEND xC_libraries ${readline_LIBRARIES})
|
||||
include_directories (${readline_INCLUDE_DIRS})
|
||||
link_directories (${readline_LIBRARY_DIRS})
|
||||
else ()
|
||||
list (APPEND xC_libraries readline)
|
||||
endif ()
|
||||
elseif (WANT_LIBEDIT)
|
||||
pkg_check_modules (libedit REQUIRED libedit)
|
||||
list (APPEND xC_libraries ${libedit_LIBRARIES})
|
||||
include_directories (${libedit_INCLUDE_DIRS})
|
||||
set (xF_SATISFIED FALSE)
|
||||
if (ncursesw_FOUND AND Unistring_FOUND)
|
||||
set (xF_SATISFIED TRUE)
|
||||
endif ()
|
||||
option (WITH_XF "Build the xF frontend" "${xF_SATISFIED}")
|
||||
if (WITH_XF AND NOT xF_SATISFIED)
|
||||
message (FATAL_ERROR "Some xF dependencies were not found")
|
||||
endif ()
|
||||
|
||||
pkg_check_modules (x11 x11 xrender xft fontconfig libpng)
|
||||
option (WITH_X11 "Build xF with X11 support" "${x11_FOUND}")
|
||||
if (WITH_X11 AND NOT x11_FOUND)
|
||||
message (FATAL_ERROR "Some X11 libraries were not found")
|
||||
endif ()
|
||||
|
||||
pkg_check_modules (lcms2 lcms2)
|
||||
option (WITH_LCMS2 "Build xF with X11 colour management" "${lcms2_FOUND}")
|
||||
|
||||
pkg_check_modules (canberra libcanberra)
|
||||
set (canberra_SATISFIED FALSE)
|
||||
if (WITH_X11 AND canberra_FOUND)
|
||||
set (canberra_SATISFIED TRUE)
|
||||
endif ()
|
||||
option (WITH_CANBERRA "Build xF with libcanberra sound support"
|
||||
"${canberra_SATISFIED}")
|
||||
if (WITH_CANBERRA AND NOT WITH_X11)
|
||||
message (FATAL_ERROR "libcanberra support requires X11 support")
|
||||
elseif (WITH_CANBERRA AND NOT canberra_FOUND)
|
||||
message (FATAL_ERROR "libcanberra not found")
|
||||
endif ()
|
||||
|
||||
# Generate a configuration file
|
||||
set (HAVE_READLINE "${WANT_READLINE}")
|
||||
set (HAVE_EDITLINE "${WANT_LIBEDIT}")
|
||||
set (HAVE_LUA "${WITH_LUA}")
|
||||
set (HAVE_LUA "${WITH_LUA}")
|
||||
set (HAVE_X11 "${WITH_X11}")
|
||||
set (HAVE_LCMS2 "${WITH_LCMS2}")
|
||||
set (HAVE_CANBERRA "${WITH_CANBERRA}")
|
||||
|
||||
include (GNUInstallDirs)
|
||||
set (project_config ${PROJECT_BINARY_DIR}/config.h)
|
||||
@@ -177,23 +206,42 @@ add_custom_target (xC-proto DEPENDS ${PROJECT_BINARY_DIR}/xC-proto.c)
|
||||
|
||||
# Build
|
||||
foreach (name xB xC xD)
|
||||
list (APPEND project_binaries ${name})
|
||||
add_executable (${name} ${name}.c ${project_config})
|
||||
target_link_libraries (${name} ${project_libraries})
|
||||
target_link_libraries (${name} PRIVATE ${project_libraries})
|
||||
add_threads (${name})
|
||||
endforeach ()
|
||||
|
||||
add_dependencies (xD replies)
|
||||
add_dependencies (xC replies xC-proto)
|
||||
target_link_libraries (xC ${xC_libraries})
|
||||
target_link_libraries (xC PRIVATE ${xC_libraries})
|
||||
target_include_directories (xC PRIVATE ${Termo_INCLUDE_DIRS})
|
||||
|
||||
if (WANT_XF)
|
||||
pkg_check_modules (x11 REQUIRED x11 xrender xft fontconfig)
|
||||
include_directories (${x11_INCLUDE_DIRS})
|
||||
link_directories (${x11_LIBRARY_DIRS})
|
||||
if (WITH_XF)
|
||||
list (APPEND project_binaries xF)
|
||||
|
||||
add_executable (xF xF.c ${project_config})
|
||||
add_dependencies (xF xC-proto)
|
||||
target_link_libraries (xF ${x11_LIBRARIES} ${project_libraries})
|
||||
target_include_directories (xF PRIVATE
|
||||
${Unistring_INCLUDE_DIRS} ${Termo_INCLUDE_DIRS})
|
||||
target_link_libraries (xF PRIVATE
|
||||
${Unistring_LIBRARIES} ${Termo_LIBRARIES}
|
||||
${ncursesw_LIBRARIES} ${project_libraries})
|
||||
if (WITH_X11)
|
||||
target_include_directories (xF PRIVATE ${x11_INCLUDE_DIRS})
|
||||
target_link_directories (xF PRIVATE ${x11_LIBRARY_DIRS})
|
||||
target_link_libraries (xF PRIVATE ${x11_LIBRARIES})
|
||||
endif ()
|
||||
if (WITH_LCMS2)
|
||||
target_include_directories (xF PRIVATE ${lcms2_INCLUDE_DIRS})
|
||||
target_link_directories (xF PRIVATE ${lcms2_LIBRARY_DIRS})
|
||||
target_link_libraries (xF PRIVATE ${lcms2_LIBRARIES})
|
||||
endif ()
|
||||
if (WITH_CANBERRA)
|
||||
target_include_directories (xF PRIVATE ${canberra_INCLUDE_DIRS})
|
||||
target_link_directories (xF PRIVATE ${canberra_LIBRARY_DIRS})
|
||||
target_link_libraries (xF PRIVATE ${canberra_LIBRARIES})
|
||||
endif ()
|
||||
add_threads (xF)
|
||||
endif ()
|
||||
|
||||
@@ -202,7 +250,10 @@ include (CTest)
|
||||
if (BUILD_TESTING)
|
||||
add_executable (test-xC $<TARGET_PROPERTY:xC,SOURCES>)
|
||||
set_target_properties (test-xC PROPERTIES COMPILE_DEFINITIONS TESTING)
|
||||
target_link_libraries (test-xC $<TARGET_PROPERTY:xC,LINK_LIBRARIES>)
|
||||
target_include_directories (test-xC
|
||||
PUBLIC $<TARGET_PROPERTY:xC,INCLUDE_DIRECTORIES>)
|
||||
target_link_libraries (test-xC
|
||||
PUBLIC $<TARGET_PROPERTY:xC,LINK_LIBRARIES>)
|
||||
add_threads (test-xC)
|
||||
add_dependencies (test-xC replies)
|
||||
|
||||
@@ -210,6 +261,11 @@ if (BUILD_TESTING)
|
||||
add_test (NAME custom-static-analysis
|
||||
COMMAND ${PROJECT_SOURCE_DIR}/test-static)
|
||||
endif ()
|
||||
option (BUILD_TESTING_WDYE "Build the integration test" OFF)
|
||||
if (BUILD_TESTING_WDYE)
|
||||
add_subdirectory (liberty/tools/wdye)
|
||||
add_test (NAME integration COMMAND wdye "${PROJECT_SOURCE_DIR}/test.lua")
|
||||
endif ()
|
||||
|
||||
# Various clang-based diagnostics, loads of fake positives and spam
|
||||
file (GLOB clang_tidy_sources *.c)
|
||||
@@ -226,13 +282,33 @@ add_custom_target (clang-tidy
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
|
||||
|
||||
# Installation
|
||||
install (TARGETS xB xC xD DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
install (TARGETS ${project_binaries} DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
install (FILES LICENSE DESTINATION ${CMAKE_INSTALL_DOCDIR})
|
||||
install (DIRECTORY plugins/xB/
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/xB/plugins USE_SOURCE_PERMISSIONS)
|
||||
install (DIRECTORY plugins/xC/
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/xC/plugins)
|
||||
|
||||
# Rasterize and install SVG icons
|
||||
if (WITH_XF AND WITH_X11)
|
||||
include (IconUtils)
|
||||
|
||||
set (icon_base ${PROJECT_BINARY_DIR}/icons)
|
||||
set (icon_png_list)
|
||||
foreach (icon_size 16 32 48)
|
||||
icon_to_png (xF ${PROJECT_SOURCE_DIR}/xF.svg
|
||||
${icon_size} ${icon_base} icon_png)
|
||||
list (APPEND icon_png_list ${icon_png})
|
||||
endforeach ()
|
||||
|
||||
add_custom_target (icons ALL DEPENDS ${icon_png_list})
|
||||
|
||||
install (FILES xF.svg
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps)
|
||||
install (DIRECTORY ${icon_base}
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR})
|
||||
endif ()
|
||||
|
||||
# Generate documentation from text markup
|
||||
find_program (ASCIIDOCTOR_EXECUTABLE asciidoctor)
|
||||
find_program (A2X_EXECUTABLE a2x)
|
||||
@@ -241,7 +317,7 @@ if (NOT ASCIIDOCTOR_EXECUTABLE AND NOT A2X_EXECUTABLE)
|
||||
"falling back to a substandard manual page generator")
|
||||
endif ()
|
||||
|
||||
foreach (page xB xC xD)
|
||||
foreach (page ${project_binaries})
|
||||
set (page_output "${PROJECT_BINARY_DIR}/${page}.1")
|
||||
list (APPEND project_MAN_PAGES "${page_output}")
|
||||
if (ASCIIDOCTOR_EXECUTABLE)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2014 - 2024, Přemysl Eric Janouch <p@janouch.name>
|
||||
Copyright (c) 2014 - 2026, Přemysl Eric Janouch <p@janouch.name>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted.
|
||||
|
||||
@@ -1,3 +1,70 @@
|
||||
2.4.0 (2026-09-04) "Complete"
|
||||
|
||||
* xC: general.relay_bind is now a string array
|
||||
|
||||
* xC: after the last release, added back a C-t binding to transpose characters,
|
||||
and M-Enter to insert newlines
|
||||
|
||||
* xC: removed Readline hacks from the fancy-prompt.lua plugin
|
||||
|
||||
* xC + all frontends: adjusted key bindings, most notably:
|
||||
- changed M-a to prioritize highlights when looking for activity;
|
||||
- added M-A to look for buffers in reverse order;
|
||||
- removed the old M-!;
|
||||
- replaced M-PageUp/M-PageDown with M-Up/M-Down;
|
||||
- added M-/ to supplement M-TAB.
|
||||
|
||||
* xF: reached rough feature parity with xC and xP
|
||||
|
||||
* xF: X11: now optionally colour-managed using lcms2, improved IME integration
|
||||
|
||||
* xP: fixed channel title layout for narrow browser windows
|
||||
|
||||
|
||||
2.3.0 (2026-07-31) "Clean"
|
||||
|
||||
* xC: nuked broken Readline and editline support, added a custom interface
|
||||
|
||||
* xC: added a /bindings command
|
||||
|
||||
* xC: relay sessions can now be resumed after a dropped connection (adjustable
|
||||
with general.relay_resume_timeout and general.relay_resume_log_limit);
|
||||
dead links are detected with periodic pings
|
||||
|
||||
* xC: server TLS certificate hostnames are now properly verified
|
||||
|
||||
* xC: added support for Lua 5.5
|
||||
|
||||
* xP: added a button to reconnect and resume the session if possible;
|
||||
page reloads start a new session as before
|
||||
|
||||
* prime.lua: prevented a DoS opportunity on excessively large numbers
|
||||
|
||||
* Added a terminal/X11 frontend for xC called xF
|
||||
|
||||
* Bumped relay protocol version
|
||||
|
||||
* Various bugfixes
|
||||
|
||||
|
||||
2.2.0 (2026-01-10) "Just Doing the Needful"
|
||||
|
||||
* xC: added more characters as nickname delimiters,
|
||||
so that @nick works as a highlight
|
||||
|
||||
* xC: fixed libedit crash with empty configuration, hackfixed Readline >= 8.3
|
||||
|
||||
* xC: prevented rare crashes in relay code
|
||||
|
||||
* xP: added a network lag indicator to the user interface
|
||||
|
||||
* xP: started embedding the necessary web resources,
|
||||
and making sure that the files have unique paths after change,
|
||||
so that stale copies are not cached by browsers indefinitely
|
||||
|
||||
* Bumped relay protocol version
|
||||
|
||||
|
||||
2.1.0 (2024-12-19) "Bunnyrific"
|
||||
|
||||
* xC: fixed a crash when the channel topic had too many formatting items
|
||||
@@ -235,7 +302,7 @@
|
||||
|
||||
* xC: don't show remembered channel modes on parted channels
|
||||
|
||||
* xC: fix highlight detection in colored text
|
||||
* xC: fix highlight detection in coloured text
|
||||
|
||||
* xC: fix CTCP handling for the real world and don't decode X-QUOTEs
|
||||
|
||||
@@ -338,7 +405,7 @@
|
||||
|
||||
* xC: nicknames in /names are now ordered
|
||||
|
||||
* xC: nicknames now use the 256-color terminal palette if available
|
||||
* xC: nicknames now use the 256-colour terminal palette if available
|
||||
|
||||
* xC: now we skip entries in the "addresses" list that can't be resolved
|
||||
to an address, along with displaying a more helpful message
|
||||
|
||||
+30
-41
@@ -10,9 +10,8 @@ They're all lean on dependencies, and offer a maximally permissive licence.
|
||||
|
||||
xC
|
||||
--
|
||||
The IRC client, and the core of 'xK'. It is largely defined by building on top
|
||||
of GNU Readline or BSD Editline that have been hacked to death. Its interface
|
||||
should feel somewhat familiar for weechat or irssi users.
|
||||
The IRC client, and the core of 'xK'. Its interface should feel somewhat
|
||||
familiar for WeeChat or irssi users.
|
||||
|
||||
image::xC.webp[align="center"]
|
||||
|
||||
@@ -33,10 +32,18 @@ including link:xC.adoc#_key_bindings[keyboard shortcuts].
|
||||
|
||||
image::xP.webp[align="center"]
|
||||
|
||||
xF
|
||||
--
|
||||
The hybrid terminal/X11 frontend for 'xC'. It has simplified word wrapping
|
||||
and limited colour support. Furthermore, X11 has simplified text shaping
|
||||
and doesn't support text selection (though in 'xC' tradition, it will happily
|
||||
launch an embedded editor on both the input and the log).
|
||||
|
||||
In general, 'xF' mimics 'xP' and adds back a bunch of lost 'xC' UI features.
|
||||
|
||||
xA, xT, xW, xM
|
||||
--------------
|
||||
Fyne, Qt Widgets, Win32, Cocoa frontends for 'xC'.
|
||||
Using them is not recommended.
|
||||
Experimental Fyne, Qt Widgets, Win32, Cocoa frontends for 'xC'.
|
||||
|
||||
xD
|
||||
--
|
||||
@@ -86,16 +93,17 @@ or as a https://git.janouch.name/p/nixexprs[Nix derivation].
|
||||
Building
|
||||
--------
|
||||
Build-only dependencies: CMake, pkg-config, awk, liberty (included),
|
||||
asciidoctor or asciidoc (recommended but optional) +
|
||||
asciidoctor or asciidoc (recommended but optional), rsvg-convert (for 'xF') +
|
||||
Common runtime dependencies: openssl +
|
||||
Additionally for 'xC': curses, libffi, readline >= 6.0 or libedit >= 2013-07-12,
|
||||
lua >= 5.3 (optional) +
|
||||
Additionally for 'xC': any curses, lua >= 5.3 (optional), termo (included) +
|
||||
Additionally for 'xF': ncursesw, libunistring, termo (included),
|
||||
x11 + xft + libpng (X11), lcms2 (X11, optional), libcanberra (X11, optional)
|
||||
|
||||
$ git clone --recursive https://git.janouch.name/p/xK.git
|
||||
$ mkdir xK/build
|
||||
$ cd xK/build
|
||||
$ cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DWANT_READLINE=ON -DWANT_LIBEDIT=OFF -DWITH_LUA=ON
|
||||
-DWITH_LUA=ON -DWITH_XF=ON
|
||||
$ make
|
||||
|
||||
To install the application, you can do either the usual:
|
||||
@@ -116,12 +124,14 @@ For the rest you might want to generate a configuration file:
|
||||
|
||||
$ xB --write-default-config
|
||||
$ xD --write-default-config
|
||||
$ xF --write-default-config
|
||||
|
||||
After making any necessary edits to the file (there are comments to aid you in
|
||||
doing that), simply run the appropriate program with no arguments:
|
||||
|
||||
$ xB
|
||||
$ xD
|
||||
$ xF
|
||||
|
||||
'xB' stays running in the foreground, therefore I recommend launching it inside
|
||||
a Screen or tmux session.
|
||||
@@ -130,18 +140,20 @@ a Screen or tmux session.
|
||||
file or something like `killall` if you want to terminate it. You can run it
|
||||
as a `forking` type systemd user service.
|
||||
|
||||
xP
|
||||
~~
|
||||
Frontends
|
||||
~~~~~~~~~
|
||||
The precondition for running 'xC' frontends is enabling its relay interface:
|
||||
|
||||
/set general.relay_bind = "127.0.0.1:9000"
|
||||
|
||||
To build the web server, you'll need to install the Go compiler, and run `make`
|
||||
from the _xP_ directory. Then start it from the _public_ subdirectory,
|
||||
and navigate to the adress you gave it as its first argument--in the following
|
||||
example, that would be http://localhost:8080[]:
|
||||
xP
|
||||
~~
|
||||
To build the web server, install the Go compiler, and run `make`
|
||||
from the _xP_ directory. Then start the resulting binary, and navigate to
|
||||
the adress you give it as its first argument--in the following example,
|
||||
that would be http://localhost:8080[]:
|
||||
|
||||
$ ../xP 127.0.0.1:8080 127.0.0.1:9000
|
||||
$ ./xP 127.0.0.1:8080 127.0.0.1:9000
|
||||
|
||||
For remote use, it's recommended to put 'xP' behind a reverse proxy, with TLS,
|
||||
and some form of HTTP authentication. Pass the external URL of the WebSocket
|
||||
@@ -156,8 +168,8 @@ running `make generate` first.
|
||||
xT
|
||||
~~
|
||||
The Qt Widgets frontend is a separate CMake subproject. It generally supports
|
||||
all desktop operating systems. To avoid having to specify the relay address
|
||||
each time you run it, pass it on the command line.
|
||||
all desktop operating systems, Android is technically usable. To avoid having
|
||||
to specify the relay address each time you run it, pass it on the command line.
|
||||
|
||||
xW
|
||||
~~
|
||||
@@ -191,26 +203,6 @@ in the required form, use:
|
||||
|
||||
$ openssl x509 -in public.pem -outform DER | sha256sum
|
||||
|
||||
Custom Key Bindings in xC
|
||||
-------------------------
|
||||
The default and preferred frontend used in 'xC' is GNU Readline. This means
|
||||
that you can change your bindings by editing '~/.inputrc'. For example:
|
||||
|
||||
....
|
||||
# Preload with system-wide settings
|
||||
$include /etc/inputrc
|
||||
|
||||
# Make M-left and M-right reorder buffers
|
||||
$if xC
|
||||
"\e\e[C": move-buffer-right
|
||||
"\e\e[D": move-buffer-left
|
||||
$endif
|
||||
....
|
||||
|
||||
Consult the source code and the GNU Readline manual for a list of available
|
||||
functions. Also refer to the latter for the exact syntax of this file.
|
||||
Beware that you can easily break the program if you're not careful.
|
||||
|
||||
How do I make xC look like the screenshot?
|
||||
------------------------------------------
|
||||
With the defaults, 'xC' doesn't look too fancy because I don't want to have
|
||||
@@ -255,6 +247,3 @@ License
|
||||
-------
|
||||
This software is released under the terms of the 0BSD license, the text of which
|
||||
is included within the package along with the list of authors.
|
||||
|
||||
Note that 'xC' becomes GPL-licensed when you link it against GNU Readline,
|
||||
but that is not a concern of this source package. The licenses are compatible.
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
|
||||
#include "liberty/liberty.c"
|
||||
#include <arpa/inet.h>
|
||||
#include <math.h>
|
||||
#include <netinet/tcp.h>
|
||||
|
||||
static void
|
||||
@@ -108,8 +109,42 @@ tokenize_host_port (char *address, const char **port)
|
||||
return address;
|
||||
}
|
||||
|
||||
static int *
|
||||
filter_color_cube_for_acceptable_nick_colors (size_t *len)
|
||||
{
|
||||
// This is a pure function and we don't use threads, static storage is fine
|
||||
static int table[6 * 6 * 6];
|
||||
size_t len_counter = 0;
|
||||
for (int x = 0; x < (int) N_ELEMENTS (table); x++)
|
||||
{
|
||||
int r = x / 36;
|
||||
int g = (x / 6) % 6;
|
||||
int b = (x % 6);
|
||||
|
||||
// The first step is 95/255, the rest are 40/255,
|
||||
// as an approximation we can double the first step
|
||||
double linear_R = pow ((r + !!r) / 6., 2.2);
|
||||
double linear_G = pow ((g + !!g) / 6., 2.2);
|
||||
double linear_B = pow ((b + !!b) / 6., 2.2);
|
||||
|
||||
// Use the relative luminance of colours within the cube to filter
|
||||
// colours that look okay-ish on terminals with both black and white
|
||||
// backgrounds (use the test-nick-colors script to calibrate)
|
||||
double Y = 0.2126 * linear_R + 0.7152 * linear_G + 0.0722 * linear_B;
|
||||
if (Y >= .25 && Y <= .4)
|
||||
table[len_counter++] = 16 + x;
|
||||
}
|
||||
*len = len_counter;
|
||||
return table;
|
||||
}
|
||||
|
||||
// --- To be moved to liberty --------------------------------------------------
|
||||
|
||||
#define LIST_FOR_EACH_REVERSED(type, iter, tail) \
|
||||
for (type *iter = (tail), *prev; \
|
||||
(iter && (prev = iter->prev)) || iter; \
|
||||
iter = prev)
|
||||
|
||||
// FIXME: in xssl_get_error() we rely on error reasons never being NULL (i.e.,
|
||||
// all loaded), which isn't very robust.
|
||||
// TODO: check all places where this is used and see if we couldn't gain better
|
||||
@@ -134,6 +169,31 @@ xerr_describe_error (void)
|
||||
return reason;
|
||||
}
|
||||
|
||||
static bool
|
||||
str_append_c_utf8 (struct str *s, uint32_t ucs4)
|
||||
{
|
||||
if (ucs4 < 0x80)
|
||||
str_append_c (s, ucs4);
|
||||
else if (ucs4 < 0x7FF)
|
||||
str_append_data (s, (char[]) {
|
||||
0xc0 | (ucs4 >> 6),
|
||||
0x80 | (ucs4 & 0x3f) }, 2);
|
||||
else if (ucs4 < 0xFFFF)
|
||||
str_append_data (s, (char[]) {
|
||||
0xe0 | (ucs4 >> 12),
|
||||
0x80 | ((ucs4 >> 6) & 0x3f),
|
||||
0x80 | (ucs4 & 0x3f) }, 3);
|
||||
else if (ucs4 < 0x10FFFF)
|
||||
str_append_data (s, (char[]) {
|
||||
0xf0 | (ucs4 >> 18),
|
||||
0x80 | ((ucs4 >> 12) & 0x3f),
|
||||
0x80 | ((ucs4 >> 6) & 0x3f),
|
||||
0x80 | (ucs4 & 0x3f) }, 4);
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct str
|
||||
str_from_cstr (const char *cstr)
|
||||
{
|
||||
|
||||
+3
-2
@@ -6,9 +6,10 @@
|
||||
// We use the XDG Base Directory Specification, but may be installed anywhere.
|
||||
#define PROJECT_DATADIR "${CMAKE_INSTALL_FULL_DATADIR}"
|
||||
|
||||
#cmakedefine HAVE_READLINE
|
||||
#cmakedefine HAVE_EDITLINE
|
||||
#cmakedefine HAVE_LUA
|
||||
#cmakedefine HAVE_X11
|
||||
#cmakedefine HAVE_LCMS2
|
||||
#cmakedefine HAVE_CANBERRA
|
||||
|
||||
#cmakedefine01 ICONV_ACCEPTS_TRANSLIT
|
||||
|
||||
|
||||
+1
-1
Submodule liberty updated: 1930f138d4...022cce71fa
@@ -14,19 +14,7 @@
|
||||
-- OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
-- CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
--
|
||||
-- Beware that it is a hack and only goes about 90% of the way, which is why
|
||||
-- this functionality is only available as a plugin in the first place
|
||||
-- (well, and also for customizability).
|
||||
--
|
||||
-- The biggest problem is that the way we work with Readline is incompatible
|
||||
-- with multiline prompts, and normal newlines just don't work. This is being
|
||||
-- circumvented by using an overflowing single-line prompt with a specially
|
||||
-- crafted character in the rightmost column that prevents the bar's background
|
||||
-- from spilling all over the last line.
|
||||
--
|
||||
-- There is also a problem with C-r search rendering not clearing out the
|
||||
-- background but to really fix that mode, we'd have to fully reimplement it
|
||||
-- since its alternative prompt very often gets overriden by accident anyway.
|
||||
-- This might go directly to xC, though it's more customizable as a plugin.
|
||||
|
||||
xC.hook_prompt (function (hook)
|
||||
local current = xC.current_buffer
|
||||
@@ -67,11 +55,7 @@ xC.hook_prompt (function (hook)
|
||||
x = x .. " (" .. active:sub (2) .. ")"
|
||||
end
|
||||
|
||||
-- Readline 7.0.003 seems to be broken and completely corrupts the prompt.
|
||||
-- However 8.0.004 seems to be fine with these, as is libedit 20191231-3.1.
|
||||
--x = x:gsub("[\128-\255]", "?")
|
||||
|
||||
-- Align to the terminal's width and apply formatting, including the hack.
|
||||
-- Align to the terminal's width and apply formatting.
|
||||
local lines, cols = xC.get_screen_size ()
|
||||
local trailing, width = " ", xC.measure (x)
|
||||
while cols > 0 and width >= cols do
|
||||
@@ -79,10 +63,10 @@ xC.hook_prompt (function (hook)
|
||||
trailing, width = ">", xC.measure (x)
|
||||
end
|
||||
|
||||
-- xC automatically smartly wraps the line.
|
||||
x = "\x01\x1b[0;4;1;38;5;16m\x1b[48;5;" .. bg_color .. "m\x02" ..
|
||||
x .. string.rep (" ", cols - width - 1) ..
|
||||
"\x01\x1b[0;4;1;7;38;5;" .. bg_color .. "m\x02" ..
|
||||
trailing .. "\x01\x1b[0;1m\x02"
|
||||
x .. string.rep (" ", cols - width - 1) .. trailing ..
|
||||
"\x01\x1b[0;1m\x02"
|
||||
|
||||
local user_prefix = function (chan, user)
|
||||
for i, chan_user in ipairs (chan.users) do
|
||||
@@ -104,10 +88,6 @@ xC.hook_prompt (function (hook)
|
||||
if modes ~= "" then x = x .. "(" .. modes .. ")" end
|
||||
end
|
||||
x = x .. "] "
|
||||
else
|
||||
-- There needs to be at least one character so that the cursor
|
||||
-- doesn't get damaged by our hack in that last column
|
||||
x = x .. "> "
|
||||
end
|
||||
return x
|
||||
end)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
--
|
||||
-- prime.lua: highlight prime numbers in messages
|
||||
--
|
||||
-- Copyright (c) 2020, Přemysl Eric Janouch <p@janouch.name>
|
||||
-- Copyright (c) 2020, 2026 Přemysl Eric Janouch <p@janouch.name>
|
||||
--
|
||||
-- Permission to use, copy, modify, and/or distribute this software for any
|
||||
-- purpose with or without fee is hereby granted.
|
||||
@@ -34,6 +34,7 @@ xC.setup_config {
|
||||
-- The prime test is actually very fast, so there is no DoS concern
|
||||
local do_intercolour = function (text)
|
||||
return tostring (text:gsub ("%f[%w_]%d+", function (n)
|
||||
if tonumber (n) > math.maxinteger then return nil end
|
||||
if tonumber (n) < smallest then return nil end
|
||||
for i = 2, n ^ (1 / 2) do if (n % i) == 0 then return nil end end
|
||||
return highlight .. n .. highlight
|
||||
|
||||
Submodule
+1
Submodule termo added at a8f3f6eca3
@@ -1,52 +0,0 @@
|
||||
#!/usr/bin/expect -f
|
||||
# Very basic end-to-end testing for CI
|
||||
set tempdir [exec mktemp -d]
|
||||
set ::env(XDG_CONFIG_HOME) $tempdir
|
||||
|
||||
# Run the daemon to test against
|
||||
system ./xD --write-default-cfg
|
||||
spawn ./xD -d
|
||||
|
||||
# 10 seconds is a bit too much
|
||||
set timeout 5
|
||||
|
||||
spawn ./xC
|
||||
|
||||
# Fuck this Tcl shit, I want the exit code
|
||||
expect_after {
|
||||
eof {
|
||||
puts ""
|
||||
puts "Child exited prematurely"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# Connect to the daemon
|
||||
send "/server add localhost\n"
|
||||
expect "]"
|
||||
send "/set servers.localhost.addresses = \"localhost\"\n"
|
||||
expect "Option changed"
|
||||
send "/disconnect\n"
|
||||
expect "]"
|
||||
send "/connect\n"
|
||||
expect "Welcome to"
|
||||
|
||||
# Try some chatting
|
||||
send "/join #test\n"
|
||||
expect "has joined"
|
||||
send "Hello\n"
|
||||
expect "Hello"
|
||||
|
||||
# Attributes
|
||||
send "\x1bmbBold text! \x1bmc0,5And colors.\n"
|
||||
expect "]"
|
||||
|
||||
# Try basic commands
|
||||
send "/set\n"
|
||||
expect "]"
|
||||
send "/help\n"
|
||||
expect "]"
|
||||
|
||||
# Quit
|
||||
send "/quit\n"
|
||||
expect "Shutting down"
|
||||
+1
-1
@@ -9,7 +9,7 @@ export example=$(
|
||||
#define N_ELEMENTS(a) (sizeof (a) / sizeof ((a)[0]))
|
||||
|
||||
$(perl -0777 -ne 'print $& if /^.*?\nfilter_color(?s:.*?)^}$/m' \
|
||||
"$(dirname "$0")"/xC.c)
|
||||
"$(dirname "$0")"/common.c)
|
||||
|
||||
void main () {
|
||||
size_t len = 0;
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env wdye
|
||||
-- Very basic end-to-end testing for CI
|
||||
function exec (...)
|
||||
local p = wdye.spawn(...)
|
||||
local out = wdye.expect(p:eof {function (p) return p[0] end})
|
||||
if not out then
|
||||
error "exec() timeout"
|
||||
end
|
||||
|
||||
local status = p:wait()
|
||||
if status ~= 0 then
|
||||
io.write(out, "\n")
|
||||
error("exit status " .. status)
|
||||
end
|
||||
return out:gsub("%s+$", "")
|
||||
end
|
||||
|
||||
local temp = exec {"mktemp", "-d"}
|
||||
local atexit = {}
|
||||
setmetatable(atexit, {__gc = function () exec {"rm", "-rf", "--", temp} end})
|
||||
|
||||
local env = {XDG_CONFIG_HOME=temp, TERM="xterm"}
|
||||
exec {"./xD", "--write-default-cfg", environ=env}
|
||||
|
||||
-- Run the daemon to test against (assuming the default port 6667)
|
||||
local xD = wdye.spawn {"./xD", "-d", environ=env}
|
||||
local xC = wdye.spawn {"./xC", environ=env}
|
||||
|
||||
function send (...) xC:send(...) end
|
||||
function expect (string)
|
||||
wdye.expect(xC:exact {string},
|
||||
wdye.timeout {5, function (p) error "xC timeout" end},
|
||||
xC:eof {function (p) error "xC exited prematurely" end})
|
||||
end
|
||||
|
||||
expect "]"
|
||||
|
||||
-- Connect to the daemon
|
||||
send "/server add localhost\n"
|
||||
expect "]"
|
||||
send "/set servers.localhost.addresses = \"localhost\"\n"
|
||||
expect "Option changed"
|
||||
send "/disconnect\n"
|
||||
expect "]"
|
||||
send "/connect\n"
|
||||
expect "Welcome to"
|
||||
|
||||
-- Try some chatting
|
||||
send "/join #test\n"
|
||||
expect "has joined"
|
||||
send "Hello\n"
|
||||
expect "Hello"
|
||||
|
||||
-- Attributes
|
||||
send "\x1bmbBold text! \x1bmc0,5And colors.\n"
|
||||
expect "]"
|
||||
|
||||
-- Try basic commands
|
||||
send "/set\n"
|
||||
expect "]"
|
||||
send "/help\n"
|
||||
expect "]"
|
||||
|
||||
-- Quit
|
||||
send "/quit\n"
|
||||
expect "Shutting down"
|
||||
|
||||
local s1 = xC:wait()
|
||||
assert(s1 == 0, "xC exited abnormally: " .. s1)
|
||||
|
||||
-- Send SIGINT (^C)
|
||||
xD:send "\003"
|
||||
local s2 = xD:wait()
|
||||
assert(s2 == 0, "xD exited abnormally: " .. s2)
|
||||
@@ -1,4 +1,5 @@
|
||||
/xA
|
||||
/xA.apk
|
||||
/proto.go
|
||||
/FyneApp.toml
|
||||
/*.png
|
||||
|
||||
@@ -18,6 +18,10 @@ FyneApp.toml: ../xK-version
|
||||
Version = '$$(cat ../xK-version)'\n\
|
||||
Build = 1\n\
|
||||
\n\
|
||||
[Migrations]\n\
|
||||
# This is temporary, for Fyne 2.8\n\
|
||||
fyneDo = true\n\
|
||||
\n\
|
||||
[LinuxAndBSD]\n\
|
||||
GenericName = 'IRC Client'\n\
|
||||
Categories = ['Network', 'Chat', 'IRCClient']\n" > $@
|
||||
@@ -32,5 +36,7 @@ proto.go: $(tools)/lxdrgen.awk $(tools)/lxdrgen-go.awk ../xC.lxdr
|
||||
xA: xA.go ../xK-version $(generated)
|
||||
go build -ldflags "-X 'main.projectVersion=$$(cat ../xK-version)'" -o $@ \
|
||||
-gcflags=all="-N -l"
|
||||
xA.apk: $(generated)
|
||||
fyne package -os android
|
||||
clean:
|
||||
rm -f $(outputs)
|
||||
|
||||
@@ -1,41 +1,47 @@
|
||||
module janouch.name/xK/xA
|
||||
|
||||
go 1.22
|
||||
go 1.26
|
||||
|
||||
require (
|
||||
fyne.io/fyne/v2 v2.5.2
|
||||
github.com/ebitengine/oto/v3 v3.3.1
|
||||
fyne.io/fyne/v2 v2.8.0
|
||||
github.com/ebitengine/oto/v3 v3.4.0
|
||||
)
|
||||
|
||||
require (
|
||||
fyne.io/systray v1.11.0 // indirect
|
||||
github.com/BurntSushi/toml v1.4.0 // indirect
|
||||
fyne.io/systray v1.12.2 // indirect
|
||||
github.com/BurntSushi/toml v1.6.0 // indirect
|
||||
github.com/FyshOS/fancyfs v0.0.1 // indirect
|
||||
github.com/anthonynsimon/bild v0.16.1 // indirect
|
||||
github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/ebitengine/purego v0.8.1 // indirect
|
||||
github.com/fredbi/uri v1.1.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.8.0 // indirect
|
||||
github.com/fyne-io/gl-js v0.0.0-20230506162202-1fdaa286a934 // indirect
|
||||
github.com/fyne-io/glfw-js v0.0.0-20240101223322-6e1efdc71b7a // indirect
|
||||
github.com/fyne-io/image v0.0.0-20240417123036-dc0ee9e7c964 // indirect
|
||||
github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71 // indirect
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a // indirect
|
||||
github.com/go-text/render v0.2.0 // indirect
|
||||
github.com/go-text/typesetting v0.2.0 // indirect
|
||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||
github.com/gopherjs/gopherjs v1.17.2 // indirect
|
||||
github.com/jeandeaual/go-locale v0.0.0-20240223122105-ce5225dcaa49 // indirect
|
||||
github.com/ebitengine/purego v0.10.1 // indirect
|
||||
github.com/fredbi/uri v1.1.1 // indirect
|
||||
github.com/fsnotify/fsnotify v1.10.1 // indirect
|
||||
github.com/fyne-io/gl-js v0.2.1-0.20260315212741-029c47fd27e8 // indirect
|
||||
github.com/fyne-io/glfw-js v0.4.0 // indirect
|
||||
github.com/fyne-io/image v0.1.1 // indirect
|
||||
github.com/fyne-io/oksvg v0.2.0 // indirect
|
||||
github.com/go-gl/gl v0.0.0-20260331235117-4566fea9a276 // indirect
|
||||
github.com/go-gl/glfw/v3.4/glfw v0.1.0-pre.1.0.20260707082822-2a407d02d01a // indirect
|
||||
github.com/go-text/render v0.2.1 // indirect
|
||||
github.com/go-text/typesetting v0.3.4 // indirect
|
||||
github.com/godbus/dbus/v5 v5.2.2 // indirect
|
||||
github.com/hack-pad/go-indexeddb v0.3.2 // indirect
|
||||
github.com/hack-pad/safejs v0.1.1 // indirect
|
||||
github.com/jeandeaual/go-locale v0.0.0-20250612000132-0ef82f21eade // indirect
|
||||
github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25 // indirect
|
||||
github.com/nicksnyder/go-i18n/v2 v2.4.1 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.24 // indirect
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
|
||||
github.com/nicksnyder/go-i18n/v2 v2.6.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/rymdport/portal v0.3.0 // indirect
|
||||
github.com/rymdport/portal v0.4.2 // indirect
|
||||
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c // indirect
|
||||
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef // indirect
|
||||
github.com/stretchr/testify v1.9.0 // indirect
|
||||
github.com/yuin/goldmark v1.7.8 // indirect
|
||||
golang.org/x/image v0.22.0 // indirect
|
||||
golang.org/x/mobile v0.0.0-20241108191957-fa514ef75a0f // indirect
|
||||
golang.org/x/net v0.31.0 // indirect
|
||||
golang.org/x/sys v0.27.0 // indirect
|
||||
golang.org/x/text v0.20.0 // indirect
|
||||
github.com/stretchr/testify v1.11.1 // indirect
|
||||
github.com/yuin/goldmark v1.8.4 // indirect
|
||||
golang.org/x/image v0.44.0 // indirect
|
||||
golang.org/x/net v0.57.0 // indirect
|
||||
golang.org/x/sys v0.47.0 // indirect
|
||||
golang.org/x/text v0.40.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
@@ -1,659 +1,93 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
|
||||
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
|
||||
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
|
||||
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
|
||||
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
fyne.io/fyne/v2 v2.5.2 h1:eSyGTmSkv10yAdAeHpDet6u2KkKxOGFc14kQu81We7Q=
|
||||
fyne.io/fyne/v2 v2.5.2/go.mod h1:26gqPDvtaxHeyct+C0BBjuGd2zwAJlPkUGSBrb+d7Ug=
|
||||
fyne.io/systray v1.11.0 h1:D9HISlxSkx+jHSniMBR6fCFOUjk1x/OOOJLa9lJYAKg=
|
||||
fyne.io/systray v1.11.0/go.mod h1:RVwqP9nYMo7h5zViCBHri2FgjXF7H2cub7MAq4NSoLs=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
|
||||
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
fyne.io/fyne/v2 v2.8.0 h1:KNUdIk1eKsXSPy/wU6MdiR1hppAPvyzbjPbtJ8h6EUQ=
|
||||
fyne.io/fyne/v2 v2.8.0/go.mod h1:tLJK7CVtUBOnMiSDR+J88t/quiGuEhwGs09tIVM1RXg=
|
||||
fyne.io/systray v1.12.2 h1:Y8DZxgLHsVQt6rY9Zrkkg+j67S7vv/1F2viOWKPpVeA=
|
||||
fyne.io/systray v1.12.2/go.mod h1:RVwqP9nYMo7h5zViCBHri2FgjXF7H2cub7MAq4NSoLs=
|
||||
github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
|
||||
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/FyshOS/fancyfs v0.0.1 h1:kgvm7VvwOMLkYTqSflplp62SlMVWQ2uAoHw9CXwXHYg=
|
||||
github.com/FyshOS/fancyfs v0.0.1/go.mod h1:S5SHVz/5R72iCXOxCqdcyTPSlg3JxNd0gaHyGBSrY8A=
|
||||
github.com/anthonynsimon/bild v0.16.1 h1:ECqtLkQ15kqfHdRtzUfNvQniJtHNpzdVU/7feMYAm0o=
|
||||
github.com/anthonynsimon/bild v0.16.1/go.mod h1:hYAxurnswTQ9dexoiK922MepdXLC1lBzG35n6ypk//g=
|
||||
github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk=
|
||||
github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/ebitengine/oto/v3 v3.3.1 h1:d4McwGQuXOT0GL7bA5g9ZnaUEIEjQvG3hafzMy+T3qE=
|
||||
github.com/ebitengine/oto/v3 v3.3.1/go.mod h1:MZeb/lwoC4DCOdiTIxYezrURTw7EvK/yF863+tmBI+U=
|
||||
github.com/ebitengine/purego v0.8.1 h1:sdRKd6plj7KYW33EH5As6YKfe8m9zbN9JMrOjNVF/BE=
|
||||
github.com/ebitengine/purego v0.8.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/ebitengine/oto/v3 v3.4.0 h1:br0PgASsEWaoWn38b2Goe7m1GKFYfNgnsjSd5Gg+/bQ=
|
||||
github.com/ebitengine/oto/v3 v3.4.0/go.mod h1:IOleLVD0m+CMak3mRVwsYY8vTctQgOM0iiL6S7Ar7eI=
|
||||
github.com/ebitengine/purego v0.10.1 h1:dewVBCBT2GaMu1SrNTYxQhgQBethzfhiwvZiLGP/qyY=
|
||||
github.com/ebitengine/purego v0.10.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g=
|
||||
github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw=
|
||||
github.com/fredbi/uri v1.1.0 h1:OqLpTXtyRg9ABReqvDGdJPqZUxs8cyBDOMXBbskCaB8=
|
||||
github.com/fredbi/uri v1.1.0/go.mod h1:aYTUoAXBOq7BLfVJ8GnKmfcuURosB1xyHDIfWeC/iW4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
|
||||
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/fyne-io/gl-js v0.0.0-20230506162202-1fdaa286a934 h1:dZC5aKobSN07hf71oMivxUmAofFja5GrfPK2rBlttX4=
|
||||
github.com/fyne-io/gl-js v0.0.0-20230506162202-1fdaa286a934/go.mod h1:d4clgH0/GrRwWjRzJJQXxT/h1TyuNSfF/X64zb/3Ggg=
|
||||
github.com/fyne-io/glfw-js v0.0.0-20240101223322-6e1efdc71b7a h1:ybgRdYvAHTn93HW79bLiBiJwVL4jVeyGQRZMgImoeWs=
|
||||
github.com/fyne-io/glfw-js v0.0.0-20240101223322-6e1efdc71b7a/go.mod h1:gsGA2dotD4v0SR6PmPCYvS9JuOeMwAtmfvDE7mbYXMY=
|
||||
github.com/fyne-io/image v0.0.0-20240417123036-dc0ee9e7c964 h1:0pTELtjlVAVGSazfwRNcqTVzqmkWb1GsNozCmmZfdZA=
|
||||
github.com/fyne-io/image v0.0.0-20240417123036-dc0ee9e7c964/go.mod h1:J9Uunu842kOcTjzQj4Eq8XIDmF55szvT1PTS1cUb1UE=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6/go.mod h1:9YTyiznxEY1fVinfM7RvRcjRHbw2xLBJ3AAGIT0I4Nw=
|
||||
github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71 h1:5BVwOaUSBTlVZowGO6VZGw2H/zl9nrd3eCZfYV+NfQA=
|
||||
github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71/go.mod h1:9YTyiznxEY1fVinfM7RvRcjRHbw2xLBJ3AAGIT0I4Nw=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a h1:vxnBhFDDT+xzxf1jTJKMKZw3H0swfWk9RpWbBbDK5+0=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-text/render v0.2.0 h1:LBYoTmp5jYiJ4NPqDc2pz17MLmA3wHw1dZSVGcOdeAc=
|
||||
github.com/go-text/render v0.2.0/go.mod h1:CkiqfukRGKJA5vZZISkjSYrcdtgKQWRa2HIzvwNN5SU=
|
||||
github.com/go-text/typesetting v0.2.0 h1:fbzsgbmk04KiWtE+c3ZD4W2nmCRzBqrqQOvYlwAOdho=
|
||||
github.com/go-text/typesetting v0.2.0/go.mod h1:2+owI/sxa73XA581LAzVuEBZ3WEEV2pXeDswCH/3i1I=
|
||||
github.com/go-text/typesetting-utils v0.0.0-20240317173224-1986cbe96c66 h1:GUrm65PQPlhFSKjLPGOZNPNxLCybjzjYBzjfoBGaDUY=
|
||||
github.com/go-text/typesetting-utils v0.0.0-20240317173224-1986cbe96c66/go.mod h1:DDxDdQEnB70R8owOx3LVpEFvpMK9eeH1o2r0yZhFI9o=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/fredbi/uri v1.1.1 h1:xZHJC08GZNIUhbP5ImTHnt5Ya0T8FI2VAwI/37kh2Ko=
|
||||
github.com/fredbi/uri v1.1.1/go.mod h1:4+DZQ5zBjEwQCDmXW5JdIjz0PUA+yJbvtBv+u+adr5o=
|
||||
github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho=
|
||||
github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo=
|
||||
github.com/fyne-io/gl-js v0.2.1-0.20260315212741-029c47fd27e8 h1:0kdPD/GEntpWmZEK5Zu/xE6Tr37jYCVDf9QP8lA/QK8=
|
||||
github.com/fyne-io/gl-js v0.2.1-0.20260315212741-029c47fd27e8/go.mod h1:ZcepK8vmOYLu96JoxbCKJy2ybr+g1pTnaBDdl7c3ajI=
|
||||
github.com/fyne-io/glfw-js v0.4.0 h1:I9hREBeFyI10cNIqbMKYb1PRidyPDgwob8o2la9SfQo=
|
||||
github.com/fyne-io/glfw-js v0.4.0/go.mod h1:SDchsFZh4n7nVuBoiowOhOgIBdz+qUQVeC1w9fe2yVU=
|
||||
github.com/fyne-io/image v0.1.1 h1:WH0z4H7qfvNUw5l4p3bC1q70sa5+YWVt6HCj7y4VNyA=
|
||||
github.com/fyne-io/image v0.1.1/go.mod h1:xrfYBh6yspc+KjkgdZU/ifUC9sPA5Iv7WYUBzQKK7JM=
|
||||
github.com/fyne-io/oksvg v0.2.0 h1:mxcGU2dx6nwjJsSA9PCYZDuoAcsZ/OuJlvg/Q9Njfo8=
|
||||
github.com/fyne-io/oksvg v0.2.0/go.mod h1:dJ9oEkPiWhnTFNCmRgEze+YNprJF7YRbpjgpWS4kzoI=
|
||||
github.com/go-gl/gl v0.0.0-20260331235117-4566fea9a276 h1:IO5P06Pcj9K04d+l4nrf3c2U56+dAotIFG6u4P1wAHI=
|
||||
github.com/go-gl/gl v0.0.0-20260331235117-4566fea9a276/go.mod h1:9YTyiznxEY1fVinfM7RvRcjRHbw2xLBJ3AAGIT0I4Nw=
|
||||
github.com/go-gl/glfw/v3.4/glfw v0.1.0-pre.1.0.20260707082822-2a407d02d01a h1:HWK0MBggT/T6YH7VffE10xBIhqeTq8JzIUPJXrRy87g=
|
||||
github.com/go-gl/glfw/v3.4/glfw v0.1.0-pre.1.0.20260707082822-2a407d02d01a/go.mod h1:T5Dn0JwIJOX1euPZ/iT4tq6nFYtmukjcYa7937HuYK8=
|
||||
github.com/go-text/render v0.2.1 h1:qwHhxqGUjjg4L0XyJWj7M7bpY75NZM+kBpv2Yfw5mcg=
|
||||
github.com/go-text/render v0.2.1/go.mod h1:HCCAq8MUlm/WRcXshBb4K/n+IkjeXQ1c2Ba+yICSm0A=
|
||||
github.com/go-text/typesetting v0.3.4 h1:YYurUOtEb9kGSOz4uE3k4OpBGsp1dDL8+fjCeaFamAU=
|
||||
github.com/go-text/typesetting v0.3.4/go.mod h1:4qZCQphq4KSgGTAeI0uMEkVbROgfah8BuyF5LRYr7XY=
|
||||
github.com/go-text/typesetting-utils v0.0.0-20260223113751-2d88ac90dae3 h1:drBZzMgdYPbmyXqOto4YhhJGrFIQCX94FpR4MzTCsos=
|
||||
github.com/go-text/typesetting-utils v0.0.0-20260223113751-2d88ac90dae3/go.mod h1:3/62I4La/HBRX9TcTpBj4eipLiwzf+vhI+7whTc9V7o=
|
||||
github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ=
|
||||
github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c=
|
||||
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y=
|
||||
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20211219123610-ec9572f70e60/go.mod h1:cz9oNYuRUWGdHmLF2IodMLkAhcPtXeULvcBNagUrxTI=
|
||||
github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
|
||||
github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
|
||||
github.com/goxjs/gl v0.0.0-20210104184919-e3fafc6f8f2a/go.mod h1:dy/f2gjY09hwVfIyATps4G2ai7/hLwLkc5TrPqONuXY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jeandeaual/go-locale v0.0.0-20240223122105-ce5225dcaa49 h1:Po+wkNdMmN+Zj1tDsJQy7mJlPlwGNQd9JZoPjObagf8=
|
||||
github.com/jeandeaual/go-locale v0.0.0-20240223122105-ce5225dcaa49/go.mod h1:YiutDnxPRLk5DLUFj6Rw4pRBBURZY07GFr54NdV9mQg=
|
||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/hack-pad/go-indexeddb v0.3.2 h1:DTqeJJYc1usa45Q5r52t01KhvlSN02+Oq+tQbSBI91A=
|
||||
github.com/hack-pad/go-indexeddb v0.3.2/go.mod h1:QvfTevpDVlkfomY498LhstjwbPW6QC4VC/lxYb0Kom0=
|
||||
github.com/hack-pad/safejs v0.1.1 h1:d5qPO0iQ7h2oVtpzGnLExE+Wn9AtytxIfltcS2b9KD8=
|
||||
github.com/hack-pad/safejs v0.1.1/go.mod h1:HdS+bKF1NrE72VoXZeWzxFOVQVUSqZJAG0xNCnb+Tio=
|
||||
github.com/jeandeaual/go-locale v0.0.0-20250612000132-0ef82f21eade h1:FmusiCI1wHw+XQbvL9M+1r/C3SPqKrmBaIOYwVfQoDE=
|
||||
github.com/jeandeaual/go-locale v0.0.0-20250612000132-0ef82f21eade/go.mod h1:ZDXo8KHryOWSIqnsb/CiDq7hQUYryCgdVnxbj8tDG7o=
|
||||
github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25 h1:YLvr1eE6cdCqjOe972w/cYF+FjW34v27+9Vo5106B4M=
|
||||
github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25/go.mod h1:kLgvv7o6UM+0QSf0QjAse3wReFDsb9qbZJdfexWlrQw=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
|
||||
github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
|
||||
github.com/nicksnyder/go-i18n/v2 v2.4.1 h1:zwzjtX4uYyiaU02K5Ia3zSkpJZrByARkRB4V3YPrr0g=
|
||||
github.com/nicksnyder/go-i18n/v2 v2.4.1/go.mod h1:++Pl70FR6Cki7hdzZRnEEqdc2dJt+SAGotyFg/SvZMk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mattn/go-runewidth v0.0.24 h1:cpokDiIn0MGnhdHwuWnJBITySJ20QyNGnY2kR/ay2DU=
|
||||
github.com/mattn/go-runewidth v0.0.24/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||
github.com/nicksnyder/go-i18n/v2 v2.6.1 h1:JDEJraFsQE17Dut9HFDHzCoAWGEQJom5s0TRd17NIEQ=
|
||||
github.com/nicksnyder/go-i18n/v2 v2.6.1/go.mod h1:Vee0/9RD3Quc/NmwEjzzD7VTZ+Ir7QbXocrkhOzmUKA=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA=
|
||||
github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo=
|
||||
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/rymdport/portal v0.3.0 h1:QRHcwKwx3kY5JTQcsVhmhC3TGqGQb9LFghVNUy8AdB8=
|
||||
github.com/rymdport/portal v0.3.0/go.mod h1:kFF4jslnJ8pD5uCi17brj/ODlfIidOxlgUDTO5ncnC4=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
|
||||
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
|
||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
|
||||
github.com/rymdport/portal v0.4.2 h1:7jKRSemwlTyVHHrTGgQg7gmNPJs88xkbKcIL3NlcmSU=
|
||||
github.com/rymdport/portal v0.4.2/go.mod h1:kFF4jslnJ8pD5uCi17brj/ODlfIidOxlgUDTO5ncnC4=
|
||||
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c h1:km8GpoQut05eY3GiYWEedbTT0qnSxrCjsVbb7yKY1KE=
|
||||
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c/go.mod h1:cNQ3dwVJtS5Hmnjxy6AgTPd0Inb3pW05ftPSX7NZO7Q=
|
||||
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef h1:Ch6Q+AZUxDBCVqdkI8FSpFyZDtCVBc2VmejdNrm5rRQ=
|
||||
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef/go.mod h1:nXTWP6+gD5+LUJ8krVhhoeHjvHTutPxMYl5SvkcnJNE=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic=
|
||||
github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
|
||||
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.22.0 h1:UtK5yLUzilVrkjMAZAZ34DXGpASN8i8pj8g+O+yd10g=
|
||||
golang.org/x/image v0.22.0/go.mod h1:9hPFhljd4zZ1GNSIZJ49sqbp45GKK9t6w+iXvGqZUz4=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mobile v0.0.0-20211207041440-4e6c2922fdee/go.mod h1:pe2sM7Uk+2Su1y7u/6Z8KJ24D7lepUjFZbhFOrmDfuQ=
|
||||
golang.org/x/mobile v0.0.0-20241108191957-fa514ef75a0f h1:23H/YlmTHfmmvpZ+ajKZL0qLz0+IwFOIqQA0mQbmLeM=
|
||||
golang.org/x/mobile v0.0.0-20241108191957-fa514ef75a0f/go.mod h1:UbSUP4uu/C9hw9R2CkojhXlAxvayHjBdU9aRvE+c1To=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
|
||||
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
|
||||
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
|
||||
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
||||
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.8-0.20211022200916-316ba0b74098/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
|
||||
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
|
||||
google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
|
||||
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
|
||||
google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
||||
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/yuin/goldmark v1.8.4 h1:oat/nd3U6NeQqFEL3xpEJq7d7c86NI+DbSNGAs4xnjA=
|
||||
github.com/yuin/goldmark v1.8.4/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
|
||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
golang.org/x/image v0.44.0 h1:+tDekMZED9+LrtB3G5xzRggpVh9CARjZqROla3R3R+I=
|
||||
golang.org/x/image v0.44.0/go.mod h1:V8K3KE9KKKE+pLpQDOeN18w9oacNSvy1tDOirTu4xtY=
|
||||
golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE=
|
||||
golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU=
|
||||
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
|
||||
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs=
|
||||
golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024, Přemysl Eric Janouch <p@janouch.name>
|
||||
// Copyright (c) 2024 - 2025, Přemysl Eric Janouch <p@janouch.name>
|
||||
// SPDX-License-Identifier: 0BSD
|
||||
|
||||
package main
|
||||
@@ -122,6 +122,10 @@ func (t *customTheme) Color(
|
||||
variant = theme.VariantDark
|
||||
}
|
||||
*/
|
||||
/*
|
||||
// Fyne 2.6.0 has a different bug, the Light variant is not applied:
|
||||
variant = theme.VariantLight
|
||||
*/
|
||||
|
||||
// Fuck this low contrast shit, text must be black.
|
||||
if name == theme.ColorNameForeground &&
|
||||
@@ -333,9 +337,14 @@ func relaySend(data RelayCommandData, callback callback) bool {
|
||||
CommandSeq: commandSeq,
|
||||
Data: data,
|
||||
}
|
||||
if callback != nil {
|
||||
commandCallbacks[m.CommandSeq] = callback
|
||||
if callback == nil {
|
||||
callback = func(err string, response *RelayResponseData) {
|
||||
if response == nil {
|
||||
showErrorMessage(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
commandCallbacks[m.CommandSeq] = callback
|
||||
commandSeq++
|
||||
|
||||
// TODO(p): Handle errors better.
|
||||
@@ -384,10 +393,10 @@ func bufferScrollToBottom() {
|
||||
func bufferPushLine(b *buffer, line bufferLine) {
|
||||
b.lines = append(b.lines, line)
|
||||
|
||||
// Fyne's text layouting is extremely slow.
|
||||
// This also noticeably improves performance.
|
||||
// The limit could be made configurable,
|
||||
// and we could use a ring buffer approach to storing the lines.
|
||||
if len(b.lines) > 100 {
|
||||
if len(b.lines) > 1000 {
|
||||
b.lines = slices.Delete(b.lines, 0, 1)
|
||||
}
|
||||
}
|
||||
@@ -402,10 +411,7 @@ func refreshIcon() {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent deadlocks (though it might have a race condition).
|
||||
// https://github.com/fyne-io/fyne/issues/5266
|
||||
go func() { wWindow.SetIcon(resource) }()
|
||||
wWindow.SetIcon(resource)
|
||||
}
|
||||
|
||||
func refreshTopic(topic []bufferLineItem) {
|
||||
@@ -523,6 +529,10 @@ func bufferToggleLog() {
|
||||
relaySend(RelayCommandData{Variant: &RelayCommandDataBufferLog{
|
||||
BufferName: name,
|
||||
}}, func(err string, response *RelayResponseData) {
|
||||
if response == nil {
|
||||
showErrorMessage(err)
|
||||
return
|
||||
}
|
||||
if bufferCurrent == name {
|
||||
bufferToggleLogFinish(
|
||||
err, response.Variant.(*RelayResponseDataBufferLog))
|
||||
@@ -539,6 +549,7 @@ func convertItemFormatting(
|
||||
switch data := item.Variant.(type) {
|
||||
case *RelayItemDataReset:
|
||||
*cf = defaultBufferLineItem()
|
||||
*inverse = false
|
||||
case *RelayItemDataFlipBold:
|
||||
cf.format.Bold = !cf.format.Bold
|
||||
case *RelayItemDataFlipItalic:
|
||||
@@ -546,7 +557,7 @@ func convertItemFormatting(
|
||||
case *RelayItemDataFlipUnderline:
|
||||
cf.format.Underline = !cf.format.Underline
|
||||
case *RelayItemDataFlipCrossedOut:
|
||||
// https://github.com/fyne-io/fyne/issues/1084
|
||||
cf.format.Strikethrough = !cf.format.Strikethrough
|
||||
case *RelayItemDataFlipInverse:
|
||||
*inverse = !*inverse
|
||||
case *RelayItemDataFlipMonospace:
|
||||
@@ -1043,6 +1054,11 @@ func relayProcessMessage(m *RelayEventMessage) {
|
||||
case *RelayEventDataServerRename:
|
||||
servers[data.New] = servers[data.ServerName]
|
||||
delete(servers, data.ServerName)
|
||||
for i := range buffers {
|
||||
if buffers[i].serverName == data.ServerName {
|
||||
buffers[i].serverName = data.New
|
||||
}
|
||||
}
|
||||
case *RelayEventDataServerRemove:
|
||||
delete(servers, data.ServerName)
|
||||
}
|
||||
@@ -1091,10 +1107,14 @@ func relayResetState() {
|
||||
}
|
||||
|
||||
func relayRun() {
|
||||
fyne.CurrentApp().Preferences().SetString(preferenceAddress, backendAddress)
|
||||
backendLock.Lock()
|
||||
|
||||
relayResetState()
|
||||
fyne.DoAndWait(func() {
|
||||
fyne.CurrentApp().Preferences().
|
||||
SetString(preferenceAddress, backendAddress)
|
||||
relayResetState()
|
||||
})
|
||||
|
||||
backendContext, backendCancel = context.WithCancel(context.Background())
|
||||
defer backendCancel()
|
||||
var err error
|
||||
@@ -1102,8 +1122,10 @@ func relayRun() {
|
||||
|
||||
backendLock.Unlock()
|
||||
if err != nil {
|
||||
wConnect.Show()
|
||||
showErrorMessage("Connection failed: " + err.Error())
|
||||
fyne.DoAndWait(func() {
|
||||
wConnect.Show()
|
||||
showErrorMessage("Connection failed: " + err.Error())
|
||||
})
|
||||
return
|
||||
}
|
||||
defer backendConn.Close()
|
||||
@@ -1116,19 +1138,15 @@ func relayRun() {
|
||||
}, nil)
|
||||
|
||||
relayMessages := relayMakeReceiver(backendContext, backendConn)
|
||||
Loop:
|
||||
for {
|
||||
select {
|
||||
case m, ok := <-relayMessages:
|
||||
if !ok {
|
||||
break Loop
|
||||
}
|
||||
for m := range relayMessages {
|
||||
fyne.DoAndWait(func() {
|
||||
relayProcessMessage(&m)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
wConnect.Show()
|
||||
showErrorMessage("Disconnected")
|
||||
fyne.DoAndWait(func() {
|
||||
wConnect.Show()
|
||||
showErrorMessage("Disconnected")
|
||||
})
|
||||
}
|
||||
|
||||
// --- Input line --------------------------------------------------------------
|
||||
@@ -1201,6 +1219,10 @@ func inputComplete() bool {
|
||||
Text: state.input,
|
||||
Position: uint32(len(state.input)),
|
||||
}}, func(err string, response *RelayResponseData) {
|
||||
if response == nil {
|
||||
showErrorMessage(err)
|
||||
return
|
||||
}
|
||||
if stamp := inputGetStamp(); state == stamp {
|
||||
inputCompleteFinish(state,
|
||||
err, response.Variant.(*RelayResponseDataBufferComplete))
|
||||
@@ -1275,11 +1297,11 @@ func (e *inputEntry) KeyDown(key *fyne.KeyEvent) {
|
||||
}
|
||||
|
||||
switch {
|
||||
case modifiedKey.Modifier == fyne.KeyModifierControl &&
|
||||
case modifiedKey.Modifier == fyne.KeyModifierAlt &&
|
||||
modifiedKey.KeyName == fyne.KeyP:
|
||||
inputUp()
|
||||
return
|
||||
case modifiedKey.Modifier == fyne.KeyModifierControl &&
|
||||
case modifiedKey.Modifier == fyne.KeyModifierAlt &&
|
||||
modifiedKey.KeyName == fyne.KeyN:
|
||||
inputDown()
|
||||
return
|
||||
@@ -1398,7 +1420,7 @@ func (l *customLayout) Layout(objects []fyne.CanvasObject, size fyne.Size) {
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
// rotatedBuffers returns buffer indexes starting with the current buffer.
|
||||
// rotatedBuffers returns buffer indexes starting after the current buffer.
|
||||
func rotatedBuffers() []int {
|
||||
r, start := make([]int, len(buffers)), 0
|
||||
for i := range buffers {
|
||||
@@ -1414,57 +1436,91 @@ func rotatedBuffers() []int {
|
||||
return r
|
||||
}
|
||||
|
||||
func actionBufferPrevious() {
|
||||
if r := rotatedBuffers(); len(r) <= 0 {
|
||||
} else if i := r[len(r)-1]; i == 0 {
|
||||
bufferActivate(buffers[len(buffers)-1].bufferName)
|
||||
} else {
|
||||
bufferActivate(buffers[i-1].bufferName)
|
||||
}
|
||||
}
|
||||
|
||||
func actionBufferNext() {
|
||||
if r := rotatedBuffers(); len(r) <= 0 {
|
||||
} else {
|
||||
bufferActivate(buffers[r[0]].bufferName)
|
||||
}
|
||||
}
|
||||
|
||||
func actionBufferLast() {
|
||||
if bufferLast != "" {
|
||||
bufferActivate(bufferLast)
|
||||
}
|
||||
}
|
||||
|
||||
func actionBufferActivity(backwards bool) {
|
||||
r := rotatedBuffers()
|
||||
if len(r) == 0 {
|
||||
return
|
||||
}
|
||||
r = r[:len(r)-1]
|
||||
if backwards {
|
||||
slices.Reverse(r)
|
||||
}
|
||||
for _, i := range r {
|
||||
if buffers[i].highlighted {
|
||||
bufferActivate(buffers[i].bufferName)
|
||||
return
|
||||
}
|
||||
}
|
||||
for _, i := range r {
|
||||
if buffers[i].newMessages != 0 {
|
||||
bufferActivate(buffers[i].bufferName)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var shortcuts = map[desktop.CustomShortcut]func(){
|
||||
{
|
||||
KeyName: fyne.KeyPageUp,
|
||||
Modifier: fyne.KeyModifierControl,
|
||||
}: func() {
|
||||
if r := rotatedBuffers(); len(r) <= 0 {
|
||||
} else if i := r[len(r)-1]; i == 0 {
|
||||
bufferActivate(buffers[len(buffers)-1].bufferName)
|
||||
} else {
|
||||
bufferActivate(buffers[i-1].bufferName)
|
||||
}
|
||||
},
|
||||
}: actionBufferPrevious,
|
||||
{
|
||||
KeyName: fyne.KeyUp,
|
||||
Modifier: fyne.KeyModifierAlt,
|
||||
}: actionBufferPrevious,
|
||||
{
|
||||
KeyName: fyne.KeyF5,
|
||||
Modifier: 0,
|
||||
}: actionBufferPrevious,
|
||||
{
|
||||
KeyName: fyne.KeyPageDown,
|
||||
Modifier: fyne.KeyModifierControl,
|
||||
}: func() {
|
||||
if r := rotatedBuffers(); len(r) <= 0 {
|
||||
} else {
|
||||
bufferActivate(buffers[r[0]].bufferName)
|
||||
}
|
||||
},
|
||||
}: actionBufferNext,
|
||||
{
|
||||
KeyName: fyne.KeyDown,
|
||||
Modifier: fyne.KeyModifierAlt,
|
||||
}: actionBufferNext,
|
||||
{
|
||||
KeyName: fyne.KeyF6,
|
||||
Modifier: 0,
|
||||
}: actionBufferNext,
|
||||
{
|
||||
KeyName: fyne.KeyTab,
|
||||
Modifier: fyne.KeyModifierAlt,
|
||||
}: func() {
|
||||
if bufferLast != "" {
|
||||
bufferActivate(bufferLast)
|
||||
}
|
||||
},
|
||||
{
|
||||
// XXX: This makes an assumption on the keyboard layout (we want '!').
|
||||
KeyName: fyne.Key1,
|
||||
Modifier: fyne.KeyModifierAlt | fyne.KeyModifierShift,
|
||||
}: func() {
|
||||
for _, i := range rotatedBuffers() {
|
||||
if buffers[i].highlighted {
|
||||
bufferActivate(buffers[i].bufferName)
|
||||
break
|
||||
}
|
||||
}
|
||||
},
|
||||
}: actionBufferLast,
|
||||
{
|
||||
KeyName: fyne.KeyA,
|
||||
Modifier: fyne.KeyModifierAlt,
|
||||
}: func() {
|
||||
for _, i := range rotatedBuffers() {
|
||||
if buffers[i].newMessages != 0 {
|
||||
bufferActivate(buffers[i].bufferName)
|
||||
break
|
||||
}
|
||||
}
|
||||
actionBufferActivity(false)
|
||||
},
|
||||
{
|
||||
KeyName: fyne.KeyA,
|
||||
Modifier: fyne.KeyModifierAlt | fyne.KeyModifierShift,
|
||||
}: func() {
|
||||
actionBufferActivity(true)
|
||||
},
|
||||
{
|
||||
KeyName: fyne.KeyH,
|
||||
|
||||
@@ -630,7 +630,7 @@ recovery_handler (int signum, siginfo_t *info, void *context)
|
||||
const char *signal_name = NULL, *reason = NULL;
|
||||
translate_signal_info (signum, &signal_name, info->si_code, &reason);
|
||||
|
||||
char buf[128], numbuf[8];
|
||||
char buf[128], numbuf[16];
|
||||
if (!signal_name)
|
||||
{
|
||||
snprintf (numbuf, sizeof numbuf, "%d", signum);
|
||||
|
||||
@@ -39,28 +39,27 @@ This feature may be used to preview server MOTD files.
|
||||
|
||||
Key bindings
|
||||
------------
|
||||
Most key bindings are inherited from the frontend in use, which is either GNU
|
||||
Readline or BSD editline. A few of them, however, are special to the IRC client
|
||||
or assume a different function. This is a list of all local overrides and
|
||||
their respective function names:
|
||||
The basic key bindings are inspired by GNU Readline. On top of that, there are
|
||||
some which are special to the IRC client or assume a different function.
|
||||
This is a list of all local specialties and their respective function names:
|
||||
|
||||
*M-p*::
|
||||
Go up in history for this buffer (normally mapped to *C-p*).
|
||||
*M-n*::
|
||||
Go down in history for this buffer (normally mapped to *C-n*).
|
||||
*C-p*, *F5*: *previous-buffer*::
|
||||
*C-p*, *F5*, *M-Up*: *previous-buffer*::
|
||||
Switch to the previous buffer in order.
|
||||
*C-n*, *F6*: *next-buffer*::
|
||||
*C-n*, *F6*, *M-Down*: *next-buffer*::
|
||||
Switch to the next buffer in order.
|
||||
*M-TAB*: *switch-buffer*::
|
||||
*M-/*, *M-TAB*: *switch-buffer*::
|
||||
Switch to the last buffer, i.e., the one you were in before.
|
||||
*M-0*, *M-1*, ..., *M-9*: *goto-buffer*::
|
||||
Go to the N-th buffer (normally sets a repeat counter).
|
||||
Since there is no buffer number zero, *M-0* goes to the tenth one.
|
||||
*M-!*: *goto-highlight*::
|
||||
Go to the first following buffer with an unseen highlight.
|
||||
*M-a*: *goto-activity*::
|
||||
Go to the first following buffer with unseen activity.
|
||||
*M-A*: *goto-backtivity*::
|
||||
Go to the first following/preceding buffer with an unseen highlight,
|
||||
or, if there are none, with unseen activity.
|
||||
*PageUp*: *display-backlog*::
|
||||
Show the in-memory backlog for this buffer using *general.pager*,
|
||||
which is almost certainly the *less*(1) program.
|
||||
@@ -83,13 +82,220 @@ their respective function names:
|
||||
Should there be any issues with the display, this will clear the terminal
|
||||
screen and redraw all information.
|
||||
|
||||
Additionally, *C-w* and *C-u* in editline behave the same as they would in
|
||||
Readline or the "vi" command mode, even though the "emacs" mode is enabled
|
||||
by default.
|
||||
Custom bindings
|
||||
---------------
|
||||
Edit the configuration file manually. For example, to make buffer reordering
|
||||
functions accessible:
|
||||
|
||||
Bindings can be customized in your _.inputrc_ or _.editrc_ file. Both libraries
|
||||
support conditional execution based on the program name. Beware that it is easy
|
||||
to make breaking changes.
|
||||
....
|
||||
bindings = {
|
||||
"M-Left" = "move-buffer-left"
|
||||
"M-Right" = "move-buffer-right"
|
||||
}
|
||||
....
|
||||
|
||||
You may bind any function you see in the */bindings* listing, though beware that
|
||||
you can easily break the program if you're not careful.
|
||||
|
||||
Lua plugin API
|
||||
--------------
|
||||
The API closely reflects the internal structure of the client.
|
||||
For code examples, please consult preinstalled plugins.
|
||||
|
||||
All references to internal objects are weak, and may become invalid.
|
||||
|
||||
Methods named like __:get_PROPERTY__ can also be accessed as __.PROPERTY__.
|
||||
|
||||
As a rule, properties are read-only, and strings are encoded in UTF-8.
|
||||
|
||||
*xC.buffers* ({Buffer, ...})::
|
||||
All buffers in order.
|
||||
*xC.current_buffer* (Buffer)::
|
||||
The active buffer.
|
||||
*xC.global_buffer* (Buffer)::
|
||||
The global buffer.
|
||||
*xC.servers* ({[string = Server, ...]})::
|
||||
Configured servers, indexed by their name.
|
||||
|
||||
*xC.get_screen_size*() -> integer, integer::
|
||||
Return the number of terminal lines and columns.
|
||||
*xC.hook_completion*(_callback_[, _priority_]) -> Hook::
|
||||
Register a generator _callback_ for Tab completions: +
|
||||
Hook, {buffer, line, words, location}, string -> {[string, ...]}?
|
||||
+
|
||||
* *buffer* (Buffer): Where the completion occurs.
|
||||
+
|
||||
* *line* (string): The whole input line.
|
||||
+
|
||||
* *words* ({[string, ...]}): The input line split into words.
|
||||
+
|
||||
* *location* (integer): Which word is being completed, zero-based.
|
||||
|
||||
*xC.hook_input*(_callback_[, _priority_]) -> Hook::
|
||||
Register a filter _callback_ for user-typed input: +
|
||||
Hook, Buffer, string -> string?
|
||||
*xC.hook_irc*(_callback_[, _priority_]) -> Hook::
|
||||
Register a filter _callback_ for incoming raw IRC messages: +
|
||||
Hook, Server, string -> string?
|
||||
*xC.hook_prompt*(_callback_[, _priority_]) -> Hook::
|
||||
Register a generator _callback_ for the TUI input line prompt: +
|
||||
Hook -> string?
|
||||
+
|
||||
So as to not break the display, escape any terminal control sequences
|
||||
by enclosing them between \x01 and \x02.
|
||||
*xC.measure*(_string_) -> integer::
|
||||
Determine the width of a _string_ in terms of terminal cells.
|
||||
*xC.parse*(_message_) -> {tags, prefix, command, params}::
|
||||
Parse a raw IRC _message_ into its components:
|
||||
+
|
||||
* *tags* ({[string = string, ...]})
|
||||
+
|
||||
* *prefix* (string?)
|
||||
+
|
||||
* *command* (string?)
|
||||
+
|
||||
* *params* ({[string, ...]})
|
||||
|
||||
*xC.setup_config*(_options_)::
|
||||
Declare persistent plugin configuration under _plugins.NAME_, with the name
|
||||
derived from the script's basename without any extensions.
|
||||
The _options_ index configuration items by name, as further tables with:
|
||||
+
|
||||
* *type* (string): The configuration type of the value: one of _null_,
|
||||
_object_, _boolean_, _integer_, _string_, __string_array__.
|
||||
+
|
||||
* *comment* (string?): The description of the value.
|
||||
+
|
||||
* *default* (string?): The default value, expressed in terms of
|
||||
the configuration language. Items with a default may not become _null_.
|
||||
+
|
||||
* *on_change* (function?): Called when the value is initialized,
|
||||
first read, or later changed.
|
||||
+
|
||||
* *validate* (function?): Called to validate values after they pass a type
|
||||
check, returning _true_ if a change should be allowed.
|
||||
|
||||
Async Library
|
||||
~~~~~~~~~~~~~
|
||||
Within this concurency model, use Lua's *coroutine.yield* like *await*.
|
||||
|
||||
*xC.async.dial*(_host_, _service_) -> WaitChannel::
|
||||
Connect to the server at _host_, port _service_. Make sure
|
||||
to set the appropriate callbacks on the returned Connection object.
|
||||
*xC.async.go*(_fn_, ...) -> Task::
|
||||
Run _fn_ as a coroutine. These coroutines may only yield WaitChannels.
|
||||
When yielding multiple wait channel values, the operation will return
|
||||
the index of the completed channel, followed by all its return values packed
|
||||
into a single table.
|
||||
*xC.async.timer_ms*(_milliseconds_) -> WaitChannel::
|
||||
Resume the calling task after the given number of _milliseconds_.
|
||||
|
||||
Buffer
|
||||
~~~~~~
|
||||
*.channel* (Channel?)::
|
||||
The associated channel, if any.
|
||||
*.hide_unimportant* (boolean)::
|
||||
Whether unimportant messages are hidden in the user interface.
|
||||
*.highlighted* (boolean)::
|
||||
Whether we've been highlighted since last seeing the buffer.
|
||||
*.name* (string)::
|
||||
The full name of the buffer.
|
||||
*.new_messages_count* (integer)::
|
||||
The number of new messages since last seeing the buffer.
|
||||
*.new_unimportant_count* (integer)::
|
||||
How many of those messages are unimportant.
|
||||
*.server* (Server?)::
|
||||
The associated server, if any.
|
||||
*.user* (User?)::
|
||||
The associated user, if any.
|
||||
|
||||
*:execute*(_input_)::
|
||||
Process a line of _input_ within the buffer, as if the user typed it in.
|
||||
*:log*(_message_)::
|
||||
Log a status _message_.
|
||||
|
||||
Channel
|
||||
~~~~~~~
|
||||
*.left_manually* (boolean)::
|
||||
Whether we've left the channel manually, not to rejoin on reconnect.
|
||||
*.name* (string)::
|
||||
The channel's literal name, which may not be in UTF-8.
|
||||
*.no_param_modes* (string)::
|
||||
Active no-parameter channel modes.
|
||||
*.param_modes* ({[string = string, ...]})::
|
||||
Active parametrized channel modes.
|
||||
*.topic* (string)::
|
||||
The channel topic, which may not be in UTF-8.
|
||||
This string includes any in-line formatting.
|
||||
*.users_len* (integer)::
|
||||
The number of users on the channel.
|
||||
|
||||
*:get_users*() -> {[{prefixes = string, user = User}, ...]}::
|
||||
Return all users on the channel, together with their prefixes.
|
||||
|
||||
Connection
|
||||
~~~~~~~~~~
|
||||
*.on_data*(_data_)::
|
||||
Called whenever _data_ is received from the server.
|
||||
*.on_eof*()::
|
||||
Called when the connection is closed by the server.
|
||||
*.on_error*(_error_)::
|
||||
Called when the connection sees an _error_.
|
||||
|
||||
*:close*()::
|
||||
Close the connection.
|
||||
*:send*(_data_)::
|
||||
Send a string to the server.
|
||||
|
||||
Hook
|
||||
~~~~
|
||||
*:unhook*()::
|
||||
Forget about the hook.
|
||||
|
||||
Server
|
||||
~~~~~~
|
||||
*.autoaway_active* (boolean)::
|
||||
Whether we've currently automatically marked ourselves away.
|
||||
*.buffer* (Buffer)::
|
||||
The server's buffer.
|
||||
*.cap_echo_message* (boolean)::
|
||||
Whether the echo-message capability is active.
|
||||
*.irc_user_host* (string)::
|
||||
Our own user's user@host as we know it, used for message splitting.
|
||||
*.manual_disconnect* (boolean)::
|
||||
A flag to avoid reconnecting automatically after a manual disconnect request
|
||||
causes a connection interrupt.
|
||||
*.name* (string)::
|
||||
The name of the server.
|
||||
*.reconnect_attempt* (integer)::
|
||||
Attempt counter while establishing a connection.
|
||||
//*.state* (integer)::
|
||||
// The connection state as an integer constant. Overriden.
|
||||
*.user* (User?)::
|
||||
Our own user, once we're registered.
|
||||
*.user_mode* (string)::
|
||||
Our own user's modes.
|
||||
|
||||
*:get_state*() -> string::
|
||||
The connection state: one of _disconnected_, _connecting_, _connected_,
|
||||
_registered_, _closing_, _half-closed_.
|
||||
*:send*(_message_)::
|
||||
Send an IRC message verbatim, after appending newline characters.
|
||||
|
||||
Task
|
||||
~~~~
|
||||
*:cancel*()::
|
||||
Cancel the task, interrupting any *yield*.
|
||||
|
||||
User
|
||||
~~~~
|
||||
*.away* (boolean)::
|
||||
Whether the user is marked away.
|
||||
*.nickname* (string)::
|
||||
The user's literal nickname, which may not be in UTF-8.
|
||||
|
||||
*:get_channels*() -> {[Channel, ...]}::
|
||||
Return all channels the user shares with us.
|
||||
|
||||
Environment
|
||||
-----------
|
||||
@@ -113,10 +319,6 @@ _/usr/local/share/xC/plugins/_::
|
||||
_/usr/share/xC/plugins/_::
|
||||
Plugins are searched for in these directories, in order.
|
||||
|
||||
Bugs
|
||||
----
|
||||
The editline (libedit) frontend may exhibit some unexpected behaviour.
|
||||
|
||||
Reporting bugs
|
||||
--------------
|
||||
Use https://git.janouch.name/p/xK to report bugs, request features,
|
||||
@@ -124,4 +326,4 @@ or submit pull requests.
|
||||
|
||||
See also
|
||||
--------
|
||||
*less*(1), *readline*(3) or *editline*(7)
|
||||
*less*(1), *xF*(1)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
// Backwards-compatible protocol version.
|
||||
const VERSION = 1;
|
||||
const VERSION = 3;
|
||||
|
||||
// From the frontend to the relay.
|
||||
// All commands receive either an Event.RESPONSE, or an Event.ERROR.
|
||||
struct CommandMessage {
|
||||
// The command sequence number will be repeated in responses
|
||||
// in the respective fields.
|
||||
@@ -12,16 +13,20 @@ struct CommandMessage {
|
||||
BUFFER_ACTIVATE,
|
||||
BUFFER_INPUT,
|
||||
BUFFER_TOGGLE_UNIMPORTANT,
|
||||
PING_RESPONSE,
|
||||
PING,
|
||||
PING_RESPONSE,
|
||||
BUFFER_COMPLETE,
|
||||
BUFFER_LOG,
|
||||
} command) {
|
||||
// If the version check succeeds, the client will receive
|
||||
// an initial stream of SERVER_UPDATE, BUFFER_UPDATE, BUFFER_STATS,
|
||||
// BUFFER_LINE, and finally a BUFFER_ACTIVATE message.
|
||||
// When a session is resumed, the RESPONSE is preceded by an event log
|
||||
// replay starting at event_seq.
|
||||
case HELLO:
|
||||
u32 version;
|
||||
// Empty to start a new session, otherwise the session to resume.
|
||||
u8 session_id<>;
|
||||
// The event_seq to continue from;
|
||||
// a new session is started when that point is no longer available.
|
||||
u32 event_seq;
|
||||
case ACTIVE:
|
||||
void;
|
||||
case BUFFER_ACTIVATE:
|
||||
@@ -32,13 +37,10 @@ struct CommandMessage {
|
||||
// XXX: Perhaps this should rather be handled through a /buffer command.
|
||||
case BUFFER_TOGGLE_UNIMPORTANT:
|
||||
string buffer_name;
|
||||
case PING_RESPONSE:
|
||||
u32 event_seq;
|
||||
|
||||
// Only these commands may produce Event.RESPONSE, as below,
|
||||
// but any command may produce an error.
|
||||
case PING:
|
||||
void;
|
||||
case PING_RESPONSE:
|
||||
u32 event_seq;
|
||||
case BUFFER_COMPLETE:
|
||||
string buffer_name;
|
||||
string text;
|
||||
@@ -52,6 +54,9 @@ struct CommandMessage {
|
||||
struct EventMessage {
|
||||
u32 event_seq;
|
||||
union EventData switch (enum Event {
|
||||
ERROR,
|
||||
RESPONSE,
|
||||
|
||||
PING,
|
||||
BUFFER_LINE,
|
||||
BUFFER_UPDATE,
|
||||
@@ -64,12 +69,34 @@ struct EventMessage {
|
||||
SERVER_UPDATE,
|
||||
SERVER_RENAME,
|
||||
SERVER_REMOVE,
|
||||
ERROR,
|
||||
RESPONSE,
|
||||
} event) {
|
||||
// Restriction: command_seq strictly follows the sequence received
|
||||
// by the relay, across both of these replies.
|
||||
case ERROR:
|
||||
u32 command_seq;
|
||||
string error;
|
||||
case RESPONSE:
|
||||
u32 command_seq;
|
||||
union ResponseData switch (Command command) {
|
||||
case HELLO:
|
||||
// The session to present on the next connection. If it differs
|
||||
// from the command, the session is new, and a full resync follows:
|
||||
// an initial stream of SERVER_UPDATE, BUFFER_UPDATE, BUFFER_STATS,
|
||||
// BUFFER_LINE, and finally a BUFFER_ACTIVATE message.
|
||||
u8 session_id<>;
|
||||
case BUFFER_COMPLETE:
|
||||
u32 start;
|
||||
string completions<>;
|
||||
case BUFFER_LOG:
|
||||
// UTF-8, but not guaranteed.
|
||||
u8 log<>;
|
||||
default:
|
||||
// Reception acknowledged.
|
||||
void;
|
||||
} data;
|
||||
|
||||
case PING:
|
||||
void;
|
||||
|
||||
case BUFFER_LINE:
|
||||
string buffer_name;
|
||||
// Whether the line should also be displayed in the active buffer.
|
||||
@@ -188,23 +215,5 @@ struct EventMessage {
|
||||
string new;
|
||||
case SERVER_REMOVE:
|
||||
string server_name;
|
||||
|
||||
// Restriction: command_seq strictly follows the sequence received
|
||||
// by the relay, across both of these replies.
|
||||
case ERROR:
|
||||
u32 command_seq;
|
||||
string error;
|
||||
case RESPONSE:
|
||||
u32 command_seq;
|
||||
union ResponseData switch (Command command) {
|
||||
case PING:
|
||||
void;
|
||||
case BUFFER_COMPLETE:
|
||||
u32 start;
|
||||
string completions<>;
|
||||
case BUFFER_LOG:
|
||||
// UTF-8, but not guaranteed.
|
||||
u8 log<>;
|
||||
} data;
|
||||
} data;
|
||||
};
|
||||
|
||||
@@ -887,7 +887,14 @@ static void
|
||||
client_unregister (struct client *c, const char *reason)
|
||||
{
|
||||
if (!c->registered)
|
||||
{
|
||||
if (c->nickname)
|
||||
{
|
||||
str_map_set (&c->ctx->users, c->nickname, NULL);
|
||||
cstr_set (&c->nickname, NULL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
char *message = xstrdup_printf (":%s!%s@%s QUIT :%s",
|
||||
c->nickname, c->username, c->hostname, reason);
|
||||
@@ -2630,7 +2637,11 @@ irc_try_kick (struct client *c, const char *channel_name, const char *nick,
|
||||
if (!(chan->modes & IRC_CHAN_MODE_QUIET))
|
||||
irc_channel_multicast (chan, message, NULL);
|
||||
else
|
||||
{
|
||||
client_send (c, "%s", message);
|
||||
if (c != client)
|
||||
client_send (client, "%s", message);
|
||||
}
|
||||
free (message);
|
||||
|
||||
channel_remove_user (chan, user);
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
xF(1)
|
||||
=====
|
||||
:doctype: manpage
|
||||
:manmanual: xK Manual
|
||||
:mansource: xK {release-version}
|
||||
|
||||
Name
|
||||
----
|
||||
xF - Terminal/X11 frontend for xC
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
*xF* [_OPTION_]... [HOST:PORT]
|
||||
|
||||
Description
|
||||
-----------
|
||||
*xF* is a frontend for the relay interface of the *xC* IRC client.
|
||||
It normally runs in the terminal, and can also use a graphical interface
|
||||
when built with support for one.
|
||||
|
||||
When an explicit relay address is given, it takes priority over configuration.
|
||||
|
||||
Options
|
||||
-------
|
||||
*-g*, *--gui*::
|
||||
Use the graphical interface even when running from a terminal.
|
||||
|
||||
*-h*, *--help*::
|
||||
Display a help message and exit.
|
||||
|
||||
*-V*, *--version*::
|
||||
Output version information and exit.
|
||||
|
||||
*--write-default-cfg*[**=**__PATH__]::
|
||||
Write a configuration file with defaults, show its path and exit.
|
||||
+
|
||||
The file will be appropriately commented.
|
||||
|
||||
Key bindings
|
||||
------------
|
||||
As in *xC*(1), with a bunch of notable additions:
|
||||
|
||||
*C-q*::
|
||||
Quit the frontend.
|
||||
*C-F5*::
|
||||
Forcefully reconnect to the relay.
|
||||
*C-o*::
|
||||
Open the last link in the transcript using *xdg-open*(1).
|
||||
*M-E*::
|
||||
Run an external editor on transcript contents, enabling, e.g., search.
|
||||
*F1*, *F2*, *M-F1*, *M-F2*::
|
||||
Scroll the buffer list: up, down, top, bottom.
|
||||
*PageUp*, *PageUp*, *M-Home*, *M-End*, *C-Home*, *C-End*::
|
||||
Scroll the transcript: up, down, top, bottom, top, bottom.
|
||||
|
||||
Reporting bugs
|
||||
--------------
|
||||
Use https://git.janouch.name/p/xK to report bugs, request features,
|
||||
or submit pull requests.
|
||||
|
||||
See also
|
||||
--------
|
||||
*xC*(1), *xdg-open*(1)
|
||||
+1
-1
@@ -1 +1 @@
|
||||
2.1.0
|
||||
2.4.0
|
||||
|
||||
+29
-15
@@ -173,8 +173,11 @@ class RelayRPC {
|
||||
func send(data: RelayCommandData, callback: Callback? = nil) {
|
||||
self.commandSeq += 1
|
||||
let m = RelayCommandMessage(commandSeq: self.commandSeq, data: data)
|
||||
if let callback = callback {
|
||||
self.commandCallbacks[m.commandSeq] = callback
|
||||
self.commandCallbacks[m.commandSeq] = callback ?? { error, data in
|
||||
if data == nil {
|
||||
NSSound.beep()
|
||||
Logger().warning("\(error)")
|
||||
}
|
||||
}
|
||||
|
||||
var w = RelayWriter()
|
||||
@@ -694,7 +697,8 @@ func refreshBuffer(b: Buffer) {
|
||||
// --- Event processing --------------------------------------------------------
|
||||
|
||||
relayRPC.onConnected = {
|
||||
let hello = RelayCommandDataHello(version: UInt32(relayVersion))
|
||||
let hello = RelayCommandDataHello(
|
||||
version: UInt32(relayVersion), sessionId: [], eventSeq: 0)
|
||||
relayRPC.send(data: hello)
|
||||
}
|
||||
|
||||
@@ -1206,7 +1210,7 @@ class WindowDelegate: NSObject, NSWindowDelegate {
|
||||
refreshBufferList()
|
||||
}
|
||||
|
||||
// Buffer indexes rotated to start after the current buffer.
|
||||
// Buffers rotated to start after the current buffer.
|
||||
func rotatedBuffers() -> Array<Buffer> {
|
||||
guard let i = relayBuffers.firstIndex(
|
||||
where: { $0.bufferName == relayBufferCurrent }) else {
|
||||
@@ -1235,22 +1239,32 @@ class WindowDelegate: NSObject, NSWindowDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
@objc func actionGotoHighlight() {
|
||||
for b in rotatedBuffers() {
|
||||
func gotoActivity(backwards: Bool) {
|
||||
var candidates = rotatedBuffers()
|
||||
candidates.popLast()
|
||||
if backwards {
|
||||
candidates.reverse()
|
||||
}
|
||||
for b in candidates {
|
||||
if b.highlighted {
|
||||
bufferActivate(name: b.bufferName)
|
||||
return
|
||||
}
|
||||
}
|
||||
for b in candidates {
|
||||
if b.newMessages != 0 {
|
||||
bufferActivate(name: b.bufferName)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc func actionGotoActivity() {
|
||||
for b in rotatedBuffers() {
|
||||
if b.newMessages != 0 {
|
||||
bufferActivate(name: b.bufferName)
|
||||
return
|
||||
}
|
||||
}
|
||||
gotoActivity(backwards: false)
|
||||
}
|
||||
|
||||
@objc func actionGotoBacktivity() {
|
||||
gotoActivity(backwards: true)
|
||||
}
|
||||
|
||||
@objc func actionToggleUnimportant() {
|
||||
@@ -1310,12 +1324,12 @@ pushAccelerator("Switch buffer",
|
||||
|
||||
// TODO(p): Remove .command, and ignore these with the right Option key.
|
||||
bufferMenu.addItem(NSMenuItem.separator())
|
||||
pushAccelerator("Go to highlight",
|
||||
#selector(WindowDelegate.actionGotoHighlight),
|
||||
"!", [.command, .option])
|
||||
pushAccelerator("Go to activity",
|
||||
#selector(WindowDelegate.actionGotoActivity),
|
||||
"a", [.command, .option])
|
||||
pushAccelerator("Go to activity backwards",
|
||||
#selector(WindowDelegate.actionGotoBacktivity),
|
||||
"a", [.shift, .command, .option])
|
||||
|
||||
bufferMenu.addItem(NSMenuItem.separator())
|
||||
pushAccelerator("Toggle unimportant",
|
||||
|
||||
@@ -247,16 +247,16 @@ func main() {
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
flag.Parse()
|
||||
if flag.NArg() < 1 {
|
||||
flag.Usage()
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
if *version {
|
||||
fmt.Printf("%s %s\n", projectName, projectVersion)
|
||||
return
|
||||
}
|
||||
|
||||
if flag.NArg() < 1 {
|
||||
flag.Usage()
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
text, err := io.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ tools = ../liberty/tools
|
||||
outputs = xP proto.go public/proto.js public/mithril.js
|
||||
all: $(outputs) public/ircfmt.woff2
|
||||
|
||||
xP: xP.go proto.go
|
||||
xP: xP.go proto.go public/proto.js public/mithril.js public/xP.css public/xP.js
|
||||
go build -o $@
|
||||
proto.go: $(tools)/lxdrgen.awk $(tools)/lxdrgen-go.awk ../xC.lxdr
|
||||
$(AWK) -f $(tools)/lxdrgen.awk -f $(tools)/lxdrgen-go.awk \
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module janouch.name/xK/xP
|
||||
|
||||
go 1.21
|
||||
go 1.22
|
||||
|
||||
toolchain go1.23.2
|
||||
|
||||
|
||||
@@ -66,6 +66,9 @@ body {
|
||||
bottom: -1px;
|
||||
background: #ccc;
|
||||
}
|
||||
.invisible {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
display: flex;
|
||||
|
||||
+143
-52
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2022 - 2024, Přemysl Eric Janouch <p@janouch.name>
|
||||
// Copyright (c) 2022 - 2026, Přemysl Eric Janouch <p@janouch.name>
|
||||
// SPDX-License-Identifier: 0BSD
|
||||
import * as Relay from './proto.js'
|
||||
|
||||
@@ -9,14 +9,40 @@ class RelayRPC extends EventTarget {
|
||||
super()
|
||||
this.url = url
|
||||
this.commandSeq = 0
|
||||
this.promised = {}
|
||||
|
||||
// Session to resume after a lost connection, and our progress in it.
|
||||
this.sessionId = ''
|
||||
this.lastEventSeq = 0
|
||||
this.connecting = false
|
||||
}
|
||||
|
||||
// FIXME: The m.redraws are contamination for properties
|
||||
// that should have an event: this.connecting, this.busy
|
||||
|
||||
// When we can't resume our session, a 'reset' event will ask for the model
|
||||
// to be reinitialized.
|
||||
connect() {
|
||||
// We can't close the connection immediately, as that queues a task.
|
||||
if (this.connecting)
|
||||
return
|
||||
this.connecting = true
|
||||
m.redraw()
|
||||
|
||||
// We can't reopen the socket immediately, as closing queues a task.
|
||||
if (this.ws === undefined)
|
||||
this._connect()
|
||||
else {
|
||||
this.ws.addEventListener('close',
|
||||
() => this._connect(), {once: true})
|
||||
this.ws.close()
|
||||
}
|
||||
}
|
||||
|
||||
_connect() {
|
||||
if (this.ws !== undefined)
|
||||
throw "Already connecting or connected"
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
new Promise((resolve, reject) => {
|
||||
let ws = this.ws = new WebSocket(this.url)
|
||||
ws.onopen = event => {
|
||||
this._initialize()
|
||||
@@ -27,6 +53,20 @@ class RelayRPC extends EventTarget {
|
||||
this.ws = undefined
|
||||
reject()
|
||||
}
|
||||
}).then(() => {
|
||||
return this.send({
|
||||
command: 'Hello',
|
||||
version: Relay.version,
|
||||
sessionId: this.sessionId,
|
||||
// Continue right after the last event we have processed.
|
||||
eventSeq: this.sessionId ? (this.lastEventSeq + 1) >>> 0 : 0,
|
||||
})
|
||||
}).catch(error => {
|
||||
// Failures manifest as a closed connection.
|
||||
console.error(error)
|
||||
}).finally(() => {
|
||||
this.connecting = false
|
||||
m.redraw()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -42,8 +82,6 @@ class RelayRPC extends EventTarget {
|
||||
this.ws.onclose = event => {
|
||||
let message = "Connection closed: " +
|
||||
event.reason + " (" + event.code + ")"
|
||||
for (const seq in this.promised)
|
||||
this.promised[seq].reject(message)
|
||||
|
||||
this.ws = undefined
|
||||
this.dispatchEvent(new CustomEvent('close', {
|
||||
@@ -52,8 +90,6 @@ class RelayRPC extends EventTarget {
|
||||
|
||||
// Now connect() can be called again.
|
||||
}
|
||||
|
||||
this.promised = {}
|
||||
}
|
||||
|
||||
_process(data) {
|
||||
@@ -66,19 +102,25 @@ class RelayRPC extends EventTarget {
|
||||
}
|
||||
|
||||
_processOne(message) {
|
||||
this.lastEventSeq = message.eventSeq
|
||||
|
||||
let e = message.data
|
||||
let p
|
||||
switch (e.event) {
|
||||
case Relay.Event.Error:
|
||||
if (this.promised[e.commandSeq] !== undefined)
|
||||
this.promised[e.commandSeq].reject(e.error)
|
||||
else
|
||||
if ((p = this.promised[e.commandSeq]) === undefined)
|
||||
console.error(`Unawaited error: ${e.error}`)
|
||||
else if (p !== true)
|
||||
p.reject(e.error)
|
||||
break
|
||||
case Relay.Event.Response:
|
||||
if (this.promised[e.commandSeq] !== undefined)
|
||||
this.promised[e.commandSeq].resolve(e.data)
|
||||
else
|
||||
if (e.data.command === Relay.Command.Hello)
|
||||
this._adoptSession(base64Encode(e.data.sessionId), e.commandSeq)
|
||||
|
||||
if ((p = this.promised[e.commandSeq]) === undefined)
|
||||
console.error("Unawaited response")
|
||||
else if (p !== true)
|
||||
p.resolve(e.data)
|
||||
break
|
||||
default:
|
||||
e.eventSeq = message.eventSeq
|
||||
@@ -89,12 +131,37 @@ class RelayRPC extends EventTarget {
|
||||
delete this.promised[e.commandSeq]
|
||||
for (const seq in this.promised) {
|
||||
// We don't particularly care about wraparound issues.
|
||||
if (seq >= e.commandSeq)
|
||||
continue
|
||||
|
||||
this.promised[seq].reject("No response")
|
||||
delete this.promised[seq]
|
||||
if (seq < e.commandSeq)
|
||||
this._abandon(seq, "No response")
|
||||
}
|
||||
m.redraw()
|
||||
}
|
||||
|
||||
_adoptSession(sessionId, seq) {
|
||||
if (sessionId === this.sessionId)
|
||||
return
|
||||
|
||||
// Nothing else can be answered from within the new session.
|
||||
for (const pending in this.promised)
|
||||
if (pending != seq)
|
||||
this._abandon(pending, "Session lost")
|
||||
|
||||
this.sessionId = sessionId
|
||||
this.dispatchEvent(new CustomEvent('reset'))
|
||||
}
|
||||
|
||||
// Stop waiting for a reply that is never going to arrive.
|
||||
_abandon(seq, message) {
|
||||
const p = this.promised[seq]
|
||||
if (p !== true)
|
||||
p.reject(message)
|
||||
delete this.promised[seq]
|
||||
}
|
||||
|
||||
get busy() {
|
||||
for (const seq in this.promised)
|
||||
return true
|
||||
return false
|
||||
}
|
||||
|
||||
send(params) {
|
||||
@@ -110,6 +177,9 @@ class RelayRPC extends EventTarget {
|
||||
|
||||
this.ws.send(JSON.stringify({commandSeq: seq, data: params}))
|
||||
|
||||
this.promised[seq] = true
|
||||
m.redraw()
|
||||
|
||||
// Automagically detect if we want a result.
|
||||
let data = undefined
|
||||
const promise = new Promise(
|
||||
@@ -127,6 +197,8 @@ class RelayRPC extends EventTarget {
|
||||
function utf8Encode(s) { return new TextEncoder().encode(s) }
|
||||
function utf8Decode(s) { return new TextDecoder().decode(s) }
|
||||
|
||||
function base64Encode(bytes) { return btoa(String.fromCharCode(...bytes)) }
|
||||
|
||||
function hasShortcutModifiers(event) {
|
||||
return (event.altKey || event.escapePrefix) &&
|
||||
!event.metaKey && !event.ctrlKey
|
||||
@@ -191,6 +263,27 @@ let bufferAutoscroll = true
|
||||
|
||||
let servers = new Map()
|
||||
|
||||
rpc.addEventListener('reset', event => {
|
||||
buffers.clear()
|
||||
bufferLast = undefined
|
||||
bufferCurrent = undefined
|
||||
bufferLog = undefined
|
||||
bufferAutoscroll = true
|
||||
|
||||
servers.clear()
|
||||
})
|
||||
|
||||
let lastActive = undefined
|
||||
|
||||
function notifyActive() {
|
||||
// Reduce unnecessary traffic.
|
||||
const now = Date.now()
|
||||
if (lastActive === undefined || (now - lastActive >= 5000)) {
|
||||
lastActive = now
|
||||
rpc.send({command: 'Active'})
|
||||
}
|
||||
}
|
||||
|
||||
function bufferResetStats(b) {
|
||||
b.newMessages = 0
|
||||
b.newUnimportantMessages = 0
|
||||
@@ -237,23 +330,7 @@ function bufferToggleLog() {
|
||||
})
|
||||
}
|
||||
|
||||
let connecting = true
|
||||
rpc.connect().then(result => {
|
||||
buffers.clear()
|
||||
bufferLast = undefined
|
||||
bufferCurrent = undefined
|
||||
bufferLog = undefined
|
||||
bufferAutoscroll = true
|
||||
|
||||
servers.clear()
|
||||
|
||||
rpc.send({command: 'Hello', version: Relay.version})
|
||||
connecting = false
|
||||
m.redraw()
|
||||
}).catch(error => {
|
||||
connecting = false
|
||||
m.redraw()
|
||||
})
|
||||
rpc.connect()
|
||||
|
||||
rpc.addEventListener('close', event => {
|
||||
m.redraw()
|
||||
@@ -998,7 +1075,7 @@ let Input = {
|
||||
|
||||
onKeyDown: event => {
|
||||
// TODO: And perhaps on other actions, too.
|
||||
rpc.send({command: 'Active'})
|
||||
notifyActive()
|
||||
|
||||
let b = buffers.get(bufferCurrent)
|
||||
if (b === undefined || event.isComposing)
|
||||
@@ -1093,7 +1170,7 @@ let Input = {
|
||||
let Main = {
|
||||
view: vnode => {
|
||||
let overlay = undefined
|
||||
if (connecting)
|
||||
if (rpc.connecting)
|
||||
overlay = m('.overlay', {}, "Connecting...")
|
||||
else if (rpc.ws === undefined)
|
||||
overlay = m('.overlay', {}, [
|
||||
@@ -1103,7 +1180,16 @@ let Main = {
|
||||
|
||||
return m('.xP', {}, [
|
||||
overlay,
|
||||
m('.title', {}, [m('b', {}, `xP`), m(Topic)]),
|
||||
m('.title', {}, [
|
||||
m('.toolbar', [
|
||||
// Midline Horizontal Ellipsis, No-Break Space
|
||||
m('span', {class: rpc.busy ? undefined : 'invisible'},
|
||||
`\u22EF\u00A0`),
|
||||
m('b', {}, `xP`),
|
||||
m('button', {onclick: () => rpc.connect()}, '⟳'),
|
||||
]),
|
||||
m(Topic),
|
||||
]),
|
||||
m('.middle', {}, [m(BufferList), m(BufferContainer)]),
|
||||
m(Status),
|
||||
m('.input', {}, [m(Prompt), m(Input)]),
|
||||
@@ -1148,10 +1234,22 @@ document.addEventListener('keydown', event => {
|
||||
return
|
||||
|
||||
// Rotate names so that the current buffer comes first.
|
||||
let names = [...buffers.keys()]
|
||||
const names = [...buffers.keys()]
|
||||
names.push.apply(names,
|
||||
names.splice(0, names.findIndex(name => name == bufferCurrent)))
|
||||
|
||||
const gotoActivity = backwards => {
|
||||
const candidates = names.slice(1)
|
||||
if (backwards)
|
||||
candidates.reverse()
|
||||
for (const name of candidates)
|
||||
if (buffers.get(name).highlighted)
|
||||
return bufferActivate(name)
|
||||
for (const name of candidates)
|
||||
if (buffers.get(name).newMessages)
|
||||
return bufferActivate(name)
|
||||
}
|
||||
|
||||
switch (event.key) {
|
||||
case 'h':
|
||||
bufferToggleLog()
|
||||
@@ -1161,28 +1259,21 @@ document.addEventListener('keydown', event => {
|
||||
bufferToggleUnimportant(bufferCurrent)
|
||||
break
|
||||
case 'a':
|
||||
for (const name of names.slice(1))
|
||||
if (buffers.get(name).newMessages) {
|
||||
bufferActivate(name)
|
||||
break
|
||||
}
|
||||
gotoActivity(false)
|
||||
break
|
||||
case '!':
|
||||
for (const name of names.slice(1))
|
||||
if (buffers.get(name).highlighted) {
|
||||
bufferActivate(name)
|
||||
break
|
||||
}
|
||||
case 'A':
|
||||
gotoActivity(true)
|
||||
break
|
||||
case 'Tab':
|
||||
case '/':
|
||||
if (bufferLast !== undefined)
|
||||
bufferActivate(bufferLast)
|
||||
break
|
||||
case 'PageUp':
|
||||
case 'ArrowUp':
|
||||
if (names.length > 1)
|
||||
bufferActivate(names.at(-1))
|
||||
break
|
||||
case 'PageDown':
|
||||
case 'ArrowDown':
|
||||
if (names.length > 1)
|
||||
bufferActivate(names.at(+1))
|
||||
break
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2022, Přemysl Eric Janouch <p@janouch.name>
|
||||
// Copyright (c) 2022 - 2025, Přemysl Eric Janouch <p@janouch.name>
|
||||
// SPDX-License-Identifier: 0BSD
|
||||
|
||||
package main
|
||||
@@ -6,12 +6,16 @@ package main
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"crypto/sha1"
|
||||
"embed"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"io/fs"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
@@ -23,7 +27,12 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
debug = flag.Bool("debug", false, "enable debug output")
|
||||
debug = flag.Bool("debug", false, "enable debug output")
|
||||
webRoot = flag.String("webroot", "", "override bundled web resources")
|
||||
|
||||
//go:embed public/*
|
||||
webResources embed.FS
|
||||
webResourcesHash string
|
||||
|
||||
addressBind string
|
||||
addressConnect string
|
||||
@@ -151,7 +160,7 @@ func clientWriteError(ctx context.Context, ws *websocket.Conn, err error) bool {
|
||||
},
|
||||
},
|
||||
}).AppendTo(nil)
|
||||
if ok {
|
||||
if !ok {
|
||||
log.Println("Event serialization failed")
|
||||
return false
|
||||
}
|
||||
@@ -167,9 +176,11 @@ func handleWS(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// AppleWebKit can be broken with compression.
|
||||
if agent := r.UserAgent(); strings.Contains(agent, " Version/") &&
|
||||
(strings.HasPrefix(agent, "Mozilla/5.0 (Macintosh; ") ||
|
||||
strings.HasPrefix(agent, "Mozilla/5.0 (iPhone; ")) {
|
||||
// It would be more reliable to check for 'ApplePaySession' in window in JS,
|
||||
// and have us disable compression based on a query parameter.
|
||||
if agent := r.UserAgent(); (strings.Contains(agent, " Version/") &&
|
||||
strings.HasPrefix(agent, "Mozilla/5.0 (Macintosh; ")) ||
|
||||
strings.HasPrefix(agent, "Mozilla/5.0 (iPhone; ") {
|
||||
opts.CompressionMode = websocket.CompressionDisabled
|
||||
}
|
||||
|
||||
@@ -240,21 +251,20 @@ func handleWS(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
var staticHandler = http.FileServer(http.Dir("."))
|
||||
|
||||
var page = template.Must(template.New("/").Parse(`<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>xP</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<base href="{{ .Root }}/">
|
||||
<link rel="stylesheet" href="xP.css" />
|
||||
</head>
|
||||
<body>
|
||||
<script src="mithril.js">
|
||||
</script>
|
||||
<script>
|
||||
let proxy = '{{ . }}'
|
||||
let proxy = '{{ .Proxy }}'
|
||||
</script>
|
||||
<script type="module" src="xP.js">
|
||||
</script>
|
||||
@@ -262,20 +272,49 @@ var page = template.Must(template.New("/").Parse(`<!DOCTYPE html>
|
||||
</html>`))
|
||||
|
||||
func handleDefault(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/" {
|
||||
staticHandler.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
wsURI := addressWS
|
||||
if wsURI == "" {
|
||||
wsURI = fmt.Sprintf("ws://%s/ws", r.Host)
|
||||
}
|
||||
if err := page.Execute(w, wsURI); err != nil {
|
||||
|
||||
args := struct {
|
||||
Root string
|
||||
Proxy string
|
||||
}{
|
||||
Root: webResourcesHash,
|
||||
Proxy: wsURI,
|
||||
}
|
||||
if err := page.Execute(w, &args); err != nil {
|
||||
log.Println("Template execution failed: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func hashFS(root fs.FS) []byte {
|
||||
hasher := sha1.New()
|
||||
callback := func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Note that this can be fooled.
|
||||
fmt.Fprintln(hasher, path)
|
||||
|
||||
if !d.IsDir() {
|
||||
file, err := root.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
io.Copy(hasher, file)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if err := fs.WalkDir(root, ".", callback); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
return hasher.Sum(nil)
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Usage = func() {
|
||||
fmt.Fprintf(flag.CommandLine.Output(),
|
||||
@@ -294,6 +333,21 @@ func main() {
|
||||
addressWS = flag.Arg(2)
|
||||
}
|
||||
|
||||
subResources, err := fs.Sub(webResources, "public")
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
if *webRoot != "" {
|
||||
subResources = os.DirFS(*webRoot)
|
||||
}
|
||||
|
||||
// The simplest way of ensuring that web browsers don't use
|
||||
// stale cached copies of our files.
|
||||
webResourcesHash = hex.EncodeToString(hashFS(subResources))
|
||||
http.Handle("/"+webResourcesHash+"/",
|
||||
http.StripPrefix("/"+webResourcesHash+"/",
|
||||
http.FileServerFS(subResources)))
|
||||
|
||||
http.Handle("/ws", http.HandlerFunc(handleWS))
|
||||
http.Handle("/", http.HandlerFunc(handleDefault))
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
/xR
|
||||
/proto.go
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
.POSIX:
|
||||
AWK = env LC_ALL=C awk
|
||||
|
||||
tools = ../liberty/tools
|
||||
generated = proto.go
|
||||
outputs = xR $(generated)
|
||||
all: $(outputs)
|
||||
generate: $(generated)
|
||||
|
||||
proto.go: $(tools)/lxdrgen.awk $(tools)/lxdrgen-go.awk ../xC.lxdr
|
||||
$(AWK) -f $(tools)/lxdrgen.awk -f $(tools)/lxdrgen-go.awk \
|
||||
-v PrefixCamel=Relay ../xC.lxdr > $@
|
||||
xR: xR.go ../xK-version $(generated)
|
||||
go build -ldflags "-X 'main.projectVersion=$$(cat ../xK-version)'" -o $@ \
|
||||
-gcflags=all="-N -l"
|
||||
clean:
|
||||
rm -f $(outputs)
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
xR(1)
|
||||
=====
|
||||
:doctype: manpage
|
||||
:manmanual: xK Manual
|
||||
:mansource: xK {release-version}
|
||||
|
||||
Name
|
||||
----
|
||||
xR - xC relay protocol analyzer
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
*xR* [_OPTION_]... RELAY-ADDRESS...
|
||||
|
||||
Description
|
||||
-----------
|
||||
*xR* connects to an *xC* relay and prints all incoming events one per line
|
||||
in JSON format. The JSON objects have two additional fields:
|
||||
|
||||
when::
|
||||
The time of reception (or sending) as a nanosecond precision
|
||||
RFC 3339 UTC timestamp.
|
||||
raw::
|
||||
The incoming event (or outgoing command) in raw binary form.
|
||||
|
||||
Options
|
||||
-------
|
||||
*-debug*::
|
||||
Print any outgoing commands as well, which may help in debugging any issues.
|
||||
|
||||
*-version*::
|
||||
Output version information and exit.
|
||||
|
||||
Reporting bugs
|
||||
--------------
|
||||
Use https://git.janouch.name/p/xK to report bugs, request features,
|
||||
or submit pull requests.
|
||||
|
||||
See also
|
||||
--------
|
||||
*xC*(1)
|
||||
@@ -0,0 +1,134 @@
|
||||
// Copyright (c) 2025, Přemysl Eric Janouch <p@janouch.name>
|
||||
// SPDX-License-Identifier: 0BSD
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
debug = flag.Bool("debug", false, "enable debug output")
|
||||
version = flag.Bool("version", false, "show version and exit")
|
||||
projectName = "xR"
|
||||
projectVersion = "?"
|
||||
)
|
||||
|
||||
func now() string {
|
||||
return time.Now().UTC().Format(time.RFC3339Nano)
|
||||
}
|
||||
|
||||
func relayReadFrame(r io.Reader) bool {
|
||||
var length uint32
|
||||
if err := binary.Read(
|
||||
r, binary.BigEndian, &length); errors.Is(err, io.EOF) {
|
||||
return false
|
||||
} else if err != nil {
|
||||
log.Fatalln("Event receive failed: " + err.Error())
|
||||
}
|
||||
b := make([]byte, length)
|
||||
if _, err := io.ReadFull(r, b); errors.Is(err, io.EOF) {
|
||||
return false
|
||||
} else if err != nil {
|
||||
log.Fatalln("Event receive failed: " + err.Error())
|
||||
}
|
||||
|
||||
m := struct {
|
||||
When string `json:"when"`
|
||||
Binary []byte `json:"raw"`
|
||||
RelayEventMessage
|
||||
}{
|
||||
When: now(),
|
||||
Binary: b,
|
||||
}
|
||||
|
||||
if after, ok := m.RelayEventMessage.ConsumeFrom(b); !ok {
|
||||
log.Println("Event deserialization failed")
|
||||
} else if len(after) != 0 {
|
||||
log.Println("Event deserialization failed: trailing data")
|
||||
return true
|
||||
}
|
||||
|
||||
j, err := json.Marshal(m)
|
||||
if err != nil {
|
||||
log.Fatalln("Event marshalling failed: " + err.Error())
|
||||
}
|
||||
fmt.Printf("%s\n", j)
|
||||
return true
|
||||
}
|
||||
|
||||
func run(addressConnect string) {
|
||||
conn, err := net.Dial("tcp", addressConnect)
|
||||
if err != nil {
|
||||
log.Println("Connection failed: " + err.Error())
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
// We can only support this one protocol version
|
||||
// that proto.go has been generated for.
|
||||
m := RelayCommandMessage{CommandSeq: 0, Data: RelayCommandData{
|
||||
Variant: &RelayCommandDataHello{Version: RelayVersion},
|
||||
}}
|
||||
|
||||
b, ok := m.AppendTo(make([]byte, 4))
|
||||
if !ok {
|
||||
log.Fatalln("Command serialization failed")
|
||||
}
|
||||
binary.BigEndian.PutUint32(b[:4], uint32(len(b)-4))
|
||||
if _, err := conn.Write(b); err != nil {
|
||||
log.Fatalln("Command send failed: " + err.Error())
|
||||
}
|
||||
|
||||
// You can differentiate the direction by the presence
|
||||
// of .data.command or .data.event.
|
||||
if *debug {
|
||||
j, err := json.Marshal(struct {
|
||||
When string `json:"when"`
|
||||
Binary []byte `json:"raw"`
|
||||
RelayCommandMessage
|
||||
}{
|
||||
When: now(),
|
||||
Binary: b,
|
||||
RelayCommandMessage: m,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalln("Command marshalling failed: " + err.Error())
|
||||
}
|
||||
fmt.Printf("%s\n", j)
|
||||
}
|
||||
|
||||
for relayReadFrame(conn) {
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Usage = func() {
|
||||
fmt.Fprintf(flag.CommandLine.Output(),
|
||||
"Usage: %s [OPTION...] CONNECT\n\n", os.Args[0])
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
flag.Parse()
|
||||
if *version {
|
||||
fmt.Printf("%s %s (relay protocol version %d)\n",
|
||||
projectName, projectVersion, RelayVersion)
|
||||
return
|
||||
}
|
||||
|
||||
if flag.NArg() != 1 {
|
||||
flag.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// TODO(p): This program should be able to run as a filter as well.
|
||||
run(flag.Arg(0))
|
||||
}
|
||||
@@ -910,6 +910,10 @@ func (c *client) nicknameOrStar() string {
|
||||
|
||||
func (c *client) unregister(reason string) {
|
||||
if !c.registered {
|
||||
if c.nickname != "" {
|
||||
delete(users, ircToCanon(c.nickname))
|
||||
c.nickname = ""
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1126,7 +1130,9 @@ func (c *client) sendLUSERS() {
|
||||
|
||||
nChannels := 0
|
||||
for _, ch := range channels {
|
||||
if 0 != ch.modes&ircChanModeSecret {
|
||||
if 0 == ch.modes&ircChanModeSecret {
|
||||
nChannels++
|
||||
} else if _, present := ch.userModes[c]; present {
|
||||
nChannels++
|
||||
}
|
||||
}
|
||||
@@ -1440,7 +1446,7 @@ func ircHandleUSER(msg *message, c *client) {
|
||||
c.realname = realname
|
||||
|
||||
c.mode = 0
|
||||
if m, err := strconv.ParseUint(mode, 10, 32); err != nil {
|
||||
if m, err := strconv.ParseUint(mode, 10, 32); err == nil {
|
||||
if 0 != m&4 {
|
||||
c.mode |= ircUserModeRxWallops
|
||||
}
|
||||
@@ -1494,7 +1500,7 @@ func ircHandleLUSERS(msg *message, c *client) {
|
||||
|
||||
func ircHandleMOTD(msg *message, c *client) {
|
||||
if len(msg.params) > 0 && !ircIsThisMe(msg.params[0]) {
|
||||
c.sendReply(ERR_NOSUCHSERVER, msg.params[1])
|
||||
c.sendReply(ERR_NOSUCHSERVER, msg.params[0])
|
||||
return
|
||||
}
|
||||
c.sendMOTD()
|
||||
@@ -1868,9 +1874,9 @@ func (mp *modeProcessor) step(modeChar byte) bool {
|
||||
case 'b':
|
||||
mp.doList(&mp.ch.banList, RPL_BANLIST, RPL_ENDOFBANLIST)
|
||||
case 'e':
|
||||
mp.doList(&mp.ch.banList, RPL_EXCEPTLIST, RPL_ENDOFEXCEPTLIST)
|
||||
mp.doList(&mp.ch.exceptionList, RPL_EXCEPTLIST, RPL_ENDOFEXCEPTLIST)
|
||||
case 'I':
|
||||
mp.doList(&mp.ch.banList, RPL_INVITELIST, RPL_ENDOFINVITELIST)
|
||||
mp.doList(&mp.ch.inviteList, RPL_INVITELIST, RPL_ENDOFINVITELIST)
|
||||
|
||||
case 'k':
|
||||
mp.doKey()
|
||||
@@ -2373,7 +2379,7 @@ func ircHandleTOPIC(msg *message, c *client) {
|
||||
}
|
||||
|
||||
ch.topic = msg.params[1]
|
||||
ch.topicWho = fmt.Sprintf("%s@%s@%s", c.nickname, c.username, c.hostname)
|
||||
ch.topicWho = fmt.Sprintf("%s!%s@%s", c.nickname, c.username, c.hostname)
|
||||
ch.topicTime = time.Now()
|
||||
|
||||
message := fmt.Sprintf(":%s!%s@%s TOPIC %s :%s",
|
||||
@@ -2397,7 +2403,7 @@ func ircTryPart(c *client, channelName string, reason string) {
|
||||
return
|
||||
}
|
||||
|
||||
message := fmt.Sprintf(":%s@%s@%s PART %s :%s",
|
||||
message := fmt.Sprintf(":%s!%s@%s PART %s :%s",
|
||||
c.nickname, c.username, c.hostname, channelName, reason)
|
||||
if 0 == ch.modes&ircChanModeQuiet {
|
||||
ircChannelMulticast(ch, message, nil)
|
||||
@@ -2454,12 +2460,15 @@ func ircTryKick(c *client, channelName, nick, reason string) {
|
||||
return
|
||||
}
|
||||
|
||||
message := fmt.Sprintf(":%s@%s@%s KICK %s %s :%s",
|
||||
message := fmt.Sprintf(":%s!%s@%s KICK %s %s :%s",
|
||||
c.nickname, c.username, c.hostname, channelName, nick, reason)
|
||||
if 0 == ch.modes&ircChanModeQuiet {
|
||||
ircChannelMulticast(ch, message, nil)
|
||||
} else {
|
||||
c.send(message)
|
||||
if c != client {
|
||||
client.send(message)
|
||||
}
|
||||
}
|
||||
|
||||
delete(ch.userModes, client)
|
||||
@@ -2485,7 +2494,7 @@ func ircHandleKICK(msg *message, c *client) {
|
||||
ircTryKick(c, targetChannels[0], targetUsers[i], reason)
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < len(channels) && i < len(targetUsers); i++ {
|
||||
for i := 0; i < len(targetChannels) && i < len(targetUsers); i++ {
|
||||
ircTryKick(c, targetChannels[i], targetUsers[i], reason)
|
||||
}
|
||||
}
|
||||
@@ -2560,7 +2569,7 @@ func ircTryJoin(c *client, channelName, key string) {
|
||||
}
|
||||
|
||||
_, invitedByChanop := c.invites[ircToCanon(channelName)]
|
||||
if 0 != ch.modes&ircChanModeInviteOnly && c.inMaskList(ch.inviteList) &&
|
||||
if 0 != ch.modes&ircChanModeInviteOnly && !c.inMaskList(ch.inviteList) &&
|
||||
!invitedByChanop {
|
||||
c.sendReply(ERR_INVITEONLYCHAN, channelName)
|
||||
return
|
||||
@@ -3113,6 +3122,7 @@ func processOneEvent() {
|
||||
capVersion: 301,
|
||||
opened: time.Now(),
|
||||
lastActive: time.Now(),
|
||||
invites: map[string]bool{},
|
||||
// TODO: Make this configurable and more fine-grained.
|
||||
antiflood: newFloodDetector(10*time.Second, 20),
|
||||
}
|
||||
|
||||
+54
-27
@@ -1,4 +1,5 @@
|
||||
# As per Qt 6.8 documentation, at least 3.16 is necessary
|
||||
# CMake 3.21 has RUNTIME_DEPENDENCY_SET.
|
||||
cmake_minimum_required (VERSION 3.21.1)
|
||||
|
||||
file (READ ../xK-version project_version)
|
||||
@@ -47,7 +48,32 @@ foreach (icon xT xT-highlighted)
|
||||
list (APPEND icon_rsrc_list "${icon_png}")
|
||||
endforeach ()
|
||||
|
||||
if (APPLE)
|
||||
function (android_mipmap_icon svg density size output_dir output)
|
||||
set (_mipmap_dir "${output_dir}/res/mipmap-${density}")
|
||||
set (_png "${_mipmap_dir}/ic_launcher.png")
|
||||
set (${output} "${_png}" PARENT_SCOPE)
|
||||
|
||||
find_program (rsvg_convert_EXECUTABLE rsvg-convert REQUIRED)
|
||||
add_custom_command (OUTPUT "${_png}"
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory "${_mipmap_dir}"
|
||||
COMMAND ${rsvg_convert_EXECUTABLE} "--output=${_png}"
|
||||
"--width=${size}" "--height=${size}" -- "${svg}"
|
||||
DEPENDS "${svg}"
|
||||
COMMENT "Generating Android ${density} application icon" VERBATIM)
|
||||
endfunction ()
|
||||
|
||||
if (ANDROID)
|
||||
set (android_base "${PROJECT_BINARY_DIR}/android")
|
||||
set (android_icon_list)
|
||||
foreach (density_size
|
||||
ldpi:36 mdpi:48 hdpi:72 xhdpi:96 xxhdpi:144 xxxhdpi:192)
|
||||
string (REPLACE ":" ";" density_size "${density_size}")
|
||||
android_mipmap_icon ("${PROJECT_SOURCE_DIR}/xT.svg"
|
||||
${density_size} "${android_base}" android_icon)
|
||||
list (APPEND android_icon_list "${android_icon}")
|
||||
endforeach ()
|
||||
add_custom_target (android-icons ALL DEPENDS ${android_icon_list})
|
||||
elseif (APPLE)
|
||||
set (MACOSX_BUNDLE_ICON_FILE xT.icns)
|
||||
icon_to_icns ("${PROJECT_SOURCE_DIR}/xT.svg"
|
||||
"${MACOSX_BUNDLE_ICON_FILE}" icon_icns)
|
||||
@@ -68,8 +94,9 @@ else ()
|
||||
|
||||
set (resource_file "${PROJECT_BINARY_DIR}/xT.rc")
|
||||
list (APPEND project_sources "${resource_file}")
|
||||
# Qt specifically looks up IDI_ICON1 and nothing else.
|
||||
add_custom_command (OUTPUT "${resource_file}"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "1 ICON \"xT.ico\""
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "IDI_ICON1 ICON \"xT.ico\""
|
||||
> ${resource_file} VERBATIM)
|
||||
set_property (SOURCE "${resource_file}"
|
||||
APPEND PROPERTY OBJECT_DEPENDS ${icon_ico})
|
||||
@@ -77,7 +104,7 @@ else ()
|
||||
endif ()
|
||||
|
||||
# Build the main executable and link it
|
||||
find_program (awk_EXECUTABLE awk ${find_program_REQUIRE})
|
||||
find_program (awk_EXECUTABLE awk REQUIRED)
|
||||
add_custom_command (OUTPUT xC-proto.cpp
|
||||
COMMAND ${CMAKE_COMMAND} -E env LC_ALL=C ${awk_EXECUTABLE}
|
||||
-f ${root}/liberty/tools/lxdrgen.awk
|
||||
@@ -97,8 +124,17 @@ qt_add_executable (xT
|
||||
add_dependencies (xT xC-proto)
|
||||
qt_add_resources (xT "rsrc" PREFIX / FILES "${beep}" ${icon_rsrc_list})
|
||||
target_link_libraries (xT PRIVATE Qt6::Widgets Qt6::Network Qt6::Multimedia)
|
||||
set_target_properties (xT PROPERTIES WIN32_EXECUTABLE ON MACOSX_BUNDLE ON
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER name.janouch.xT)
|
||||
set_target_properties (xT PROPERTIES
|
||||
WIN32_EXECUTABLE ON
|
||||
MACOSX_BUNDLE ON
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER name.janouch.xT
|
||||
QT_ANDROID_APP_NAME xT
|
||||
QT_ANDROID_APP_ICON "@mipmap/ic_launcher"
|
||||
QT_ANDROID_PACKAGE_NAME name.janouch.xT
|
||||
QT_ANDROID_PACKAGE_SOURCE_DIR "${android_base}")
|
||||
if (ANDROID)
|
||||
add_dependencies (xT android-icons)
|
||||
endif ()
|
||||
|
||||
# https://stackoverflow.com/questions/79079161 and resolved in Qt Creator 16.
|
||||
set (QT_QML_GENERATE_QMLLS_INI ON)
|
||||
@@ -110,13 +146,24 @@ if (ANDROID)
|
||||
install (TARGETS xT DESTINATION .)
|
||||
elseif (APPLE OR WIN32)
|
||||
install (TARGETS xT
|
||||
RUNTIME_DEPENDENCY_SET dependencies_xT
|
||||
BUNDLE DESTINATION .
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
# XXX: QTBUG-127075, which can be circumvented by manually running
|
||||
# macdeployqt on xT.app before the install.
|
||||
if (WIN32)
|
||||
install (RUNTIME_DEPENDENCY_SET dependencies_xT DIRECTORIES $ENV{PATH}
|
||||
PRE_EXCLUDE_REGEXES "api-ms-win-.*"
|
||||
POST_EXCLUDE_REGEXES ".*[/\\]system32[/\\].*")
|
||||
endif ()
|
||||
|
||||
qt_generate_deploy_app_script (TARGET xT OUTPUT_SCRIPT deploy_xT)
|
||||
install (SCRIPT "${deploy_xT}")
|
||||
|
||||
# At least with Homebrew Qt, you will get QTBUG-127075,
|
||||
# which can be circumvented by running macdeployqt twice.
|
||||
if (APPLE)
|
||||
install (SCRIPT "${deploy_xT}")
|
||||
endif ()
|
||||
else ()
|
||||
install (TARGETS xT DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
install (FILES ../LICENSE DESTINATION ${CMAKE_INSTALL_DOCDIR})
|
||||
@@ -129,26 +176,6 @@ else ()
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/applications)
|
||||
endif ()
|
||||
|
||||
# Within MSYS2, windeployqt doesn't copy the compiler runtime,
|
||||
# which is always linked dynamically by the Qt binaries.
|
||||
# TODO(p): Consider whether or not to use MSYS2 to cross-compile, and how.
|
||||
if (WIN32)
|
||||
install (CODE [=[
|
||||
set (bindir "${CMAKE_INSTALL_PREFIX}/bin")
|
||||
execute_process (COMMAND cygpath -m /
|
||||
OUTPUT_VARIABLE cygroot OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if (cygroot)
|
||||
execute_process (COMMAND ldd "${bindir}/xT.exe"
|
||||
OUTPUT_VARIABLE ldd_output OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
string (REGEX MATCHALL " /mingw64/bin/[^ ]+ " libs "${ldd_output}")
|
||||
foreach (lib ${libs})
|
||||
string (STRIP "${lib}" lib)
|
||||
file (COPY "${cygroot}${lib}" DESTINATION "${bindir}")
|
||||
endforeach()
|
||||
endif ()
|
||||
]=])
|
||||
endif ()
|
||||
|
||||
# CPack
|
||||
set (CPACK_PACKAGE_VENDOR "Premysl Eric Janouch")
|
||||
set (CPACK_PACKAGE_CONTACT "Přemysl Eric Janouch <p@janouch.name>")
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "xC-proto.cpp"
|
||||
#include "config.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
@@ -179,6 +180,14 @@ beep()
|
||||
|
||||
// --- Networking --------------------------------------------------------------
|
||||
|
||||
static void
|
||||
on_relay_generic_response(
|
||||
std::wstring error, const Relay::ResponseData *response)
|
||||
{
|
||||
if (!response)
|
||||
show_error_message(QString::fromStdWString(error));
|
||||
}
|
||||
|
||||
static void
|
||||
relay_send(Relay::CommandData *data, Callback callback = {})
|
||||
{
|
||||
@@ -190,6 +199,8 @@ relay_send(Relay::CommandData *data, Callback callback = {})
|
||||
|
||||
if (callback)
|
||||
g.command_callbacks[m.command_seq] = std::move(callback);
|
||||
else
|
||||
g.command_callbacks[m.command_seq] = on_relay_generic_response;
|
||||
|
||||
auto len = qToBigEndian<uint32_t>(w.data.size());
|
||||
auto prefix = reinterpret_cast<const char *>(&len);
|
||||
@@ -1110,9 +1121,12 @@ relay_process_message(const Relay::EventMessage &m)
|
||||
{
|
||||
auto &data = dynamic_cast<Relay::EventData_ServerRename &>(*m.data);
|
||||
auto original = QString::fromStdWString(data.server_name);
|
||||
g.servers.insert_or_assign(
|
||||
QString::fromStdWString(data.new_), g.servers.at(original));
|
||||
auto new_ = QString::fromStdWString(data.new_);
|
||||
g.servers.insert_or_assign(new_, g.servers.at(original));
|
||||
g.servers.erase(original);
|
||||
for (auto &b : g.buffers)
|
||||
if (b.server_name == original)
|
||||
b.server_name = new_;
|
||||
break;
|
||||
}
|
||||
case Relay::Event::SERVER_REMOVE:
|
||||
@@ -1609,6 +1623,22 @@ rotated_buffers()
|
||||
return rotated;
|
||||
}
|
||||
|
||||
static void
|
||||
goto_activity_bidirectional(bool backwards)
|
||||
{
|
||||
auto candidates = rotated_buffers();
|
||||
if (!candidates.empty())
|
||||
candidates.pop_back();
|
||||
if (backwards)
|
||||
std::reverse(candidates.begin(), candidates.end());
|
||||
for (auto i : candidates)
|
||||
if (auto &b = g.buffers[i]; b.highlighted)
|
||||
return buffer_activate(b.buffer_name);
|
||||
for (auto i : candidates)
|
||||
if (auto &b = g.buffers[i]; b.new_messages)
|
||||
return buffer_activate(b.buffer_name);
|
||||
}
|
||||
|
||||
static void
|
||||
bind_shortcuts()
|
||||
{
|
||||
@@ -1628,47 +1658,42 @@ bind_shortcuts()
|
||||
if (auto b = buffer_by_name(g.buffer_last))
|
||||
buffer_activate(b->buffer_name);
|
||||
};
|
||||
auto goto_highlight = [] {
|
||||
for (auto i : rotated_buffers())
|
||||
if (g.buffers[i].highlighted) {
|
||||
buffer_activate(g.buffers[i].buffer_name);
|
||||
break;
|
||||
}
|
||||
};
|
||||
auto goto_activity = [] {
|
||||
for (auto i : rotated_buffers())
|
||||
if (g.buffers[i].new_messages) {
|
||||
buffer_activate(g.buffers[i].buffer_name);
|
||||
break;
|
||||
}
|
||||
};
|
||||
auto toggle_unimportant = [] {
|
||||
if (auto b = buffer_by_name(g.buffer_current))
|
||||
buffer_toggle_unimportant(b->buffer_name);
|
||||
};
|
||||
auto goto_activity = [] {
|
||||
goto_activity_bidirectional(false);
|
||||
};
|
||||
auto goto_backtivity = [] {
|
||||
goto_activity_bidirectional(true);
|
||||
};
|
||||
|
||||
new QShortcut(QKeyCombination(Qt::ControlModifier, Qt::Key_Tab),
|
||||
g.wMain, switch_buffer);
|
||||
new QShortcut(QKeyCombination(Qt::AltModifier, Qt::Key_Tab),
|
||||
g.wMain, switch_buffer);
|
||||
new QShortcut(QKeyCombination(Qt::AltModifier, Qt::Key_Slash),
|
||||
g.wMain, switch_buffer);
|
||||
|
||||
new QShortcut(QKeyCombination(Qt::NoModifier, Qt::Key_F5),
|
||||
g.wMain, previous_buffer);
|
||||
new QShortcut(QKeyCombination(Qt::AltModifier, Qt::Key_PageUp),
|
||||
new QShortcut(QKeyCombination(Qt::AltModifier, Qt::Key_Up),
|
||||
g.wMain, previous_buffer);
|
||||
new QShortcut(QKeyCombination(Qt::ControlModifier, Qt::Key_PageUp),
|
||||
g.wMain, previous_buffer);
|
||||
new QShortcut(QKeyCombination(Qt::NoModifier, Qt::Key_F6),
|
||||
g.wMain, next_buffer);
|
||||
new QShortcut(QKeyCombination(Qt::AltModifier, Qt::Key_PageDown),
|
||||
new QShortcut(QKeyCombination(Qt::AltModifier, Qt::Key_Down),
|
||||
g.wMain, next_buffer);
|
||||
new QShortcut(QKeyCombination(Qt::ControlModifier, Qt::Key_PageDown),
|
||||
g.wMain, next_buffer);
|
||||
|
||||
new QShortcut(QKeyCombination(Qt::AltModifier, Qt::Key_A),
|
||||
g.wMain, goto_activity);
|
||||
new QShortcut(QKeyCombination(Qt::AltModifier, Qt::Key_Exclam),
|
||||
g.wMain, goto_highlight);
|
||||
new QShortcut(
|
||||
QKeyCombination(Qt::AltModifier | Qt::ShiftModifier, Qt::Key_A),
|
||||
g.wMain, goto_backtivity);
|
||||
new QShortcut(QKeyCombination(Qt::AltModifier, Qt::Key_H),
|
||||
g.wMain, toggle_unimportant);
|
||||
}
|
||||
|
||||
+2
-2
@@ -7,8 +7,8 @@
|
||||
#define ID_PREVIOUS_BUFFER 11
|
||||
#define ID_NEXT_BUFFER 12
|
||||
#define ID_SWITCH_BUFFER 13
|
||||
#define ID_GOTO_HIGHLIGHT 14
|
||||
#define ID_GOTO_ACTIVITY 15
|
||||
#define ID_GOTO_ACTIVITY 14
|
||||
#define ID_GOTO_BACKTIVITY 15
|
||||
#define ID_TOGGLE_UNIMPORTANT 16
|
||||
#define ID_DISPLAY_FULL_LOG 17
|
||||
|
||||
|
||||
@@ -221,6 +221,14 @@ relay_try_write(std::wstring &error)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
on_relay_generic_response(
|
||||
std::wstring error, const Relay::ResponseData *response)
|
||||
{
|
||||
if (!response)
|
||||
show_error_message(error.c_str());
|
||||
}
|
||||
|
||||
static void
|
||||
relay_send(Relay::CommandData *data, Callback callback = {})
|
||||
{
|
||||
@@ -232,6 +240,8 @@ relay_send(Relay::CommandData *data, Callback callback = {})
|
||||
|
||||
if (callback)
|
||||
g.command_callbacks[m.command_seq] = std::move(callback);
|
||||
else
|
||||
g.command_callbacks[m.command_seq] = on_relay_generic_response;
|
||||
|
||||
uint32_t len = htonl(w.data.size());
|
||||
uint8_t *prefix = reinterpret_cast<uint8_t *>(&len);
|
||||
@@ -731,7 +741,7 @@ refresh_buffer(const Buffer &b)
|
||||
// PFM_BORDER is not implemented, at most we can try to construct
|
||||
// an OLE object the width of the screen and see how it clips
|
||||
// (this is a lot of code).
|
||||
size_t i = 0, mark_before = b.lines.size() -
|
||||
int64_t i = 0, mark_before = int64_t(b.lines.size()) -
|
||||
b.new_messages - b.new_unimportant_messages;
|
||||
for (auto line = b.lines.begin(); line != b.lines.end(); ++line) {
|
||||
if (i == mark_before)
|
||||
@@ -1047,6 +1057,9 @@ relay_process_message(const Relay::EventMessage &m)
|
||||
auto &data = dynamic_cast<Relay::EventData_ServerRename &>(*m.data);
|
||||
g.servers.insert_or_assign(data.new_, g.servers.at(data.server_name));
|
||||
g.servers.erase(data.server_name);
|
||||
for (auto &b : g.buffers)
|
||||
if (b.server_name == data.server_name)
|
||||
b.server_name = data.new_;
|
||||
break;
|
||||
}
|
||||
case Relay::Event::SERVER_REMOVE:
|
||||
@@ -1602,6 +1615,21 @@ process_bufferlist_notification(WORD code)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
goto_activity(std::vector<size_t> candidates, bool backwards)
|
||||
{
|
||||
if (!candidates.empty())
|
||||
candidates.pop_back();
|
||||
if (backwards)
|
||||
std::reverse(candidates.begin(), candidates.end());
|
||||
for (auto i : candidates)
|
||||
if (auto &b = g.buffers[i]; b.highlighted)
|
||||
return buffer_activate(b.buffer_name);
|
||||
for (auto i : candidates)
|
||||
if (auto &b = g.buffers[i]; b.new_messages)
|
||||
return buffer_activate(b.buffer_name);
|
||||
}
|
||||
|
||||
static void
|
||||
process_accelerator(WORD id)
|
||||
{
|
||||
@@ -1632,19 +1660,11 @@ process_accelerator(WORD id)
|
||||
if (!g.buffer_last.empty())
|
||||
buffer_activate(g.buffer_last);
|
||||
return;
|
||||
case ID_GOTO_HIGHLIGHT:
|
||||
for (auto i : rotated)
|
||||
if (g.buffers[i].highlighted) {
|
||||
buffer_activate(g.buffers[i].buffer_name);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
case ID_GOTO_ACTIVITY:
|
||||
for (auto i : rotated)
|
||||
if (g.buffers[i].new_messages) {
|
||||
buffer_activate(g.buffers[i].buffer_name);
|
||||
break;
|
||||
}
|
||||
goto_activity(rotated, false);
|
||||
return;
|
||||
case ID_GOTO_BACKTIVITY:
|
||||
goto_activity(rotated, true);
|
||||
return;
|
||||
case ID_TOGGLE_UNIMPORTANT:
|
||||
if (b)
|
||||
|
||||
@@ -25,8 +25,8 @@ BEGIN
|
||||
VK_TAB, ID_SWITCH_BUFFER, CONTROL, VIRTKEY
|
||||
// These are proper, but llvm-rc won't accept them (GitHub #64002).
|
||||
#ifndef __clang__
|
||||
"!", ID_GOTO_HIGHLIGHT, ALT
|
||||
"a", ID_GOTO_ACTIVITY, ALT
|
||||
"A", ID_GOTO_BACKTIVITY, ALT
|
||||
"H", ID_TOGGLE_UNIMPORTANT, ALT
|
||||
"h", ID_DISPLAY_FULL_LOG, ALT
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user