xC: nuke Readline and libedit
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:
@@ -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
@@ -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)
|
||||
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user