xC: nuke Readline and libedit
Arch Linux AUR Success
Alpine 3.23 Success
OpenBSD 7.8 Scripts failed

Replace them with a custom frontend making use of the termo library.
It's a bit rough at the edges, yet thoroughly functional.

The original libraries have carried us far, but they've become more
trouble than what they're worth:

 - It's much easier to make this change than to keep fixing
   both frontends.  That has become particularly difficult as of late.

 - It's also a much smaller undertaking than rewriting the client
   in more radical ways, such as:
    - Going for headless operation (also note that we currently lack
      a terminal relay client).
    - Rewriting the entire user interface to use curses.

 - Abandoning GNU Readline clears up licencing.

 - The old interface code was full of odd hacks and wild adapters.
   While this commit adds some fresh ugly areas, in sum it's a cleanup.

 - Purging the dependencies simplifies an eventual automated rewrite
   in another language.

Some freshly invalidated issues:

 - Readline 8.3 has reworked history, and our method of circumventing
   a memory leak in history handling stopped working reliably.
   Very tough to trace.

 - Editline could block waiting on input.

 - Editline refresh.c revision 1.61 seems to have completely broken
   the prompt hiding mechanism, with no obvious means of circumventing.
This commit is contained in:
2026-07-18 01:23:55 +02:00
parent e52501a1df
commit 67d044a426
9 changed files with 1270 additions and 1743 deletions
+3
View File
@@ -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
+28 -32
View File
@@ -9,8 +9,6 @@ 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
@@ -88,10 +86,28 @@ 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
@@ -120,32 +136,8 @@ 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)
# 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})
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}")
include (GNUInstallDirs)
set (project_config ${PROJECT_BINARY_DIR}/config.h)
@@ -186,6 +178,7 @@ endforeach ()
add_dependencies (xD replies)
add_dependencies (xC replies xC-proto)
target_link_libraries (xC ${xC_libraries})
target_include_directories (xC PRIVATE ${Termo_INCLUDE_DIRS})
if (WANT_XF)
pkg_check_modules (x11 REQUIRED x11 xrender xft fontconfig)
@@ -203,7 +196,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)
+4
View File
@@ -1,5 +1,9 @@
Unreleased
* xC: nuked broken Readline and editline support, added a custom frontend
* xC: added a /bindings command
* xC: added support for Lua 5.5
* prime.lua: prevented a DoS opportunity on excessively large numbers
+5 -28
View File
@@ -10,9 +10,10 @@ 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. Currently the terminal interface
experience deserves some polishing, because we've just got rid of
Readline/Editline dependencies, which kept breaking in exciting ways.
image::xC.webp[align="center"]
@@ -88,8 +89,7 @@ Building
Build-only dependencies: CMake, pkg-config, awk, liberty (included),
asciidoctor or asciidoc (recommended but optional) +
Common runtime dependencies: openssl +
Additionally for 'xC': curses, libffi, readline >= 6.0 or libedit >= 2013-07-12,
lua >= 5.3 (optional) +
Additionally for 'xC': curses, lua >= 5.3 (optional), termo (included) +
$ git clone --recursive https://git.janouch.name/p/xK.git
$ mkdir xK/build
@@ -191,26 +191,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 +235,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.
+25
View File
@@ -134,6 +134,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)
{
-2
View File
@@ -6,8 +6,6 @@
// 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
#cmakedefine01 ICONV_ACCEPTS_TRANSLIT
Submodule
+1
Submodule termo added at a8f3f6eca3
+17 -15
View File
@@ -39,10 +39,9 @@ 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*).
@@ -83,13 +82,20 @@ 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
--------------
@@ -313,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,
@@ -324,4 +326,4 @@ or submit pull requests.
See also
--------
*less*(1), *readline*(3) or *editline*(7)
*less*(1)
+1187 -1666
View File
File diff suppressed because it is too large Load Diff