diff options
38 files changed, 445 insertions, 244 deletions
diff --git a/.fmsbw/10-freebsd14-msys-sciteco b/.fmsbw/10-freebsd14-msys-sciteco index 037ac66..f8e1f40 100755 --- a/.fmsbw/10-freebsd14-msys-sciteco +++ b/.fmsbw/10-freebsd14-msys-sciteco @@ -1,39 +1,5 @@ #!/usr/local/bin/bash set -ex -export ASSUME_ALWAYS_YES=yes - -# Already in freebsd14-sciteco -# TODO: Build this with buildah. -# Start with --network=host -#pkg update -#pkg install FreeBSD-clang FreeBSD-clibs-dev \ -# gmake pkgconf autoconf automake libtool \ -# glib gtk3 groff doxygen lowdown valgrind -# -#pkg install llvm21 gnugrep gmake coreutils gsed gawk git wget gnupg bash groff zip autoconf automake libtool python3 -#pkg remove FreeBSD-clang -#git clone https://github.com/HolyBlackCat/quasi-msys2.git /opt/quasi-msys2 -#cd /opt/quasi-msys2 -#ln -s /usr/local/bin/gpgv2 /usr/local/bin/gpgv -#ln -s /usr/local/bin/bash /bin/bash -#mkdir -p gnu-overrides -#ln -s /usr/local/bin/ggrep gnu-overrides/grep -#ln -s /usr/local/bin/gmake gnu-overrides/make -#ln -s /usr/local/bin/gsed gnu-overrides/sed -#ln -s /usr/local/bin/greadlink gnu-overrides/readlink -#ln -s /usr/local/bin/wine64 gnu-overrides/wine -#echo MINGW64 >msystem.txt -#cat >activate << EOF -#cd /opt/quasi-msys2 -#export PATH=`pwd`/gnu-overrides:$PATH -#export PKG_CONFIG=pkg-config -#set +ex -#. env/all.src -#set -ex -#EOF -#gmake install _autotools _gcc _libc++ _glib2 _pdcurses _gtk3 _librsvg -#ln -nfs "/opt/quasi-msys2/root/mingw64" /mingw64 -#pkg clean -a autoreconf -i mkdir build-freebsd @@ -75,7 +41,11 @@ cp ico/sciteco-48.png /opt/htdocs/graphics . /opt/quasi-msys2/activate cd /opt/build -export CURSES_CFLAGS=-I/mingw64/include/pdcurses/ +# NOTE: Sometimes the PDCursesMod MSYS upstream package is too old, +# so we also installed v4.5.4 into the container. +#export CURSES_CFLAGS=-I/mingw64/include/pdcurses/ +export CURSES_CFLAGS=-I/opt/PDCursesMod + # FIXME: glib on MinGW supports static linking but the gspawn # helper binaries are still linked dynamically, forcing us to ship # all DLLs anyway. Therefore it makes little sense to link SciTECO @@ -90,25 +60,31 @@ export LDFLAGS="-flto=thin -stdlib=libc++" # We cannot run Windows binaries automatically through Wine, # so we must still force cross-compilation with --host. +# There is a --with-launcher=wine64, but SciTECO is currently +# simply broken under Wine. #autoreconf -i mkdir build-wingui build-wincon cd build-wingui +# See above, we use a manually built PDCursesMod v4.5.4 +#export CURSES_LIBS="-lpdcurses_wingui -lgdi32 -lcomdlg32 -lwinmm" +export CURSES_LIBS="/opt/PDCursesMod/wingui/pdcurses.a -lgdi32 -lcomdlg32 -lwinmm" ../configure --host=x86_64-w64-mingw32 \ --with-interface=pdcurses-gui --enable-html-docs --program-prefix=g \ --with-scitecodatadir=. \ - --disable-bootstrap \ - CURSES_LIBS="-lpdcurses_wingui -lgdi32 -lcomdlg32 -lwinmm" + --disable-bootstrap make make install-strip #make check TESTSUITEFLAGS="--verbose --color=never" cd ../build-wincon +# See above, we use a manually built PDCursesMod v4.5.4 +#export CURSES_LIBS="-lpdcurses_wincon -lgdi32 -lwinmm" +export CURSES_LIBS="/opt/PDCursesMod/wincon/pdcurses.a -lgdi32 -lwinmm" ../configure --host=x86_64-w64-mingw32 \ --with-interface=pdcurses --enable-html-docs \ --with-scitecodatadir=. \ - --disable-bootstrap \ - CURSES_LIBS="-lpdcurses_wincon -lgdi32 -lwinmm" + --disable-bootstrap make make install-strip #make check TESTSUITEFLAGS="--verbose --color=never" diff --git a/.fmsbw/20-freebsd14-osx-sciteco b/.fmsbw/20-freebsd14-osx-sciteco index bef1cfb..5cbd49f 100755 --- a/.fmsbw/20-freebsd14-osx-sciteco +++ b/.fmsbw/20-freebsd14-osx-sciteco @@ -25,12 +25,14 @@ cd .. #UNATTENDED=1 ./build.sh #unset CPPFLAGS #export MACOSX_DEPLOYMENT_TARGET=10.13 -# FIXME: This is not unattended. Perhaps echo https://nue.de.packages.macports.org/macports/packages >target/macports/MIRROR +# FIXME: This is not unattended. +# Perhaps echo https://nue.de.packages.macports.org/macports/packages >target/macports/MIRROR # dylibbundler is available but can't be run naturally. +# FIXME: How to install variants, like the Quartz variant for Gtk3? #osxcross-macports install --static glib2-devel gtk3-devel # #pkg install cmake -#git clone https://github.com/auriamg/macdylibbundler.git /opt/macdylibbundler +#git clone --depth=1 https://github.com/auriamg/macdylibbundler.git /opt/macdylibbundler #cd /opt/macdylibbundler #cmake . #make @@ -68,6 +70,7 @@ cd .. # FIXME: Also build -arch arm64 and package with x86_64-apple-darwin25-lipo into universal binary. # x86_64-apple-darwin25-lipo -lipo -create -output sciteco x86_64/usr/local/bin/sciteco arm64/usr/local/bin/sciteco # TODO: Build Gtk version as well. +# Currently, we cannot install the Quartz variant. mkdir -p /opt/htdocs/downloads/nightly/ cp sciteco-curses_nightly_macos_x86_64.tar.gz /opt/htdocs/downloads/nightly/ diff --git a/.fmsbw/50-ubuntu22-appimage b/.fmsbw/50-ubuntu22-appimage index ade1100..ca987fa 100755 --- a/.fmsbw/50-ubuntu22-appimage +++ b/.fmsbw/50-ubuntu22-appimage @@ -9,15 +9,6 @@ set -ex # we run this CI job. # We should be fine, though unless committing at 6:00 in the morning. -#apt-get update -o APT::Cache-Start=100000000 -#apt-get install -o APT::Cache-Start=100000000 -y fuse libfuse2 imagemagick wget file binutils libglib2.0-bin -#mkdir -p ~/pkg2appimage -#cd ~/pkg2appimage -#wget -O pkg2appimage.AppImage https://github.com/AppImageCommunity/pkg2appimage/releases/download/continuous/pkg2appimage-1eceb30-x86_64.AppImage -#chmod +x pkg2appimage.AppImage -# FIXME: We could get automatic mounting to work with fusefs in the host and by exposesing /dev/fuse. -#./pkg2appimage.AppImage --appimage-extract - cd AppImage ~/pkg2appimage/squashfs-root/AppRun curses.yml mv out/*.AppImage /opt/htdocs/downloads/nightly/sciteco-curses_nightly_x86_64.AppImage diff --git a/.fmsbw/images/Makefile b/.fmsbw/images/Makefile new file mode 100644 index 0000000..678a05a --- /dev/null +++ b/.fmsbw/images/Makefile @@ -0,0 +1,67 @@ +# Don't build any image by default +all: + +# Base image for building SciTECO on FreeBSD. +freebsd14-sciteco: + buildah from --name $@-working --network=host quay.io/dougrabson/freebsd14.1-small + buildah config --env ASSUME_ALWAYS_YES=yes $@-working + buildah run $@-working pkg update + buildah run $@-working pkg install FreeBSD-clang FreeBSD-lld FreeBSD-libcompiler_rt-dev FreeBSD-clibs-dev \ + gmake pkgconf autoconf automake libtool \ + glib gtk3 groff doxygen lowdown valgrind + buildah run $@-working pkg clean -a + buildah commit $@-working $@ + +freebsd14-msys-sciteco: + buildah from --name $@-working --network=host freebsd14-sciteco + buildah run $@-working pkg install llvm21 gnugrep gmake coreutils gsed gawk \ + git wget gnupg bash groff zip autoconf automake libtool python3 \ + wine + #buildah run $@-working pkg remove FreeBSD-clang + buildah run $@-working pkg clean -a + # Cannot check out with --depth=1 as we need a particular commit. + buildah run $@-working git clone https://github.com/HolyBlackCat/quasi-msys2.git /opt/quasi-msys2 + buildah config --workingdir /opt/quasi-msys2 $@-working + buildah run $@-working git checkout e41c4d0f7dde15031132348875d1d01c8d0ea857 + buildah run $@-working ln -s /usr/local/bin/gpgv2 /usr/local/bin/gpgv + buildah run $@-working ln -s /usr/local/bin/bash /bin/bash + buildah run $@-working mkdir -p gnu-overrides + buildah run $@-working ln -s /usr/local/bin/ggrep gnu-overrides/grep + buildah run $@-working ln -s /usr/local/bin/gmake gnu-overrides/make + buildah run $@-working ln -s /usr/local/bin/gsed gnu-overrides/sed + buildah run $@-working ln -s /usr/local/bin/greadlink gnu-overrides/readlink + buildah run $@-working ln -s /usr/local/bin/wine64 gnu-overrides/wine + buildah run $@-working bash -c 'echo MINGW64 >msystem.txt' + buildah copy $@-working msys-activate activate + buildah run $@-working gmake install _autotools _gcc _libc++ _glib2 _pdcurses _gtk3 _librsvg + buildah run $@-working ln -nfs "/opt/quasi-msys2/root/mingw64" /mingw64 + # The upstream _pdcurses package is often too outdated, so we also build from sources. + # TOOD: Build this with -flto. + buildah run $@-working git clone --depth=1 -b v4.5.4 https://github.com/Bill-Gray/PDCursesMod.git /opt/PDCursesMod + buildah run $@-working bash -c '. /opt/quasi-msys2/activate && gmake -j2 -C /opt/PDCursesMod/wincon CC=$$CC AR=$$AR WIDE=Y UTF8=Y' + buildah run $@-working bash -c '. /opt/quasi-msys2/activate && gmake -j2 -C /opt/PDCursesMod/wingui CC=$$CC AR=$$AR WIDE=Y UTF8=Y' + buildah commit $@-working $@ + +freebsd14-osx-sciteco: + false # TODO + +APT_GET = apt-get -o APT::Cache-Start=100000000 --yes + +ubuntu22-appimage: + buildah from --name $@-working --network=host --os=linux ubuntu:22.04 + buildah run $@-working $(APT_GET) update + buildah run $@-working $(APT_GET) install fuse libfuse2 imagemagick wget file binutils libglib2.0-bin + buildah run $@-working $(APT_GET) clean + buildah run $@-working mkdir -p ~/pkg2appimage + buildah config --workingdir '~/pkg2appimage' $@-working + buildah run $@-working wget -O pkg2appimage.AppImage \ + https://github.com/AppImageCommunity/pkg2appimage/releases/download/continuous/pkg2appimage-1eceb30-x86_64.AppImage + buildah run $@-working chmod +x pkg2appimage.AppImage + # FIXME: We could get automatic mounting to work with fusefs in the host and by exposing /dev/fuse. + # FIXME: This does not run without /proc. + buildah run $@-working ./pkg2appimage.AppImage --appimage-extract + buildah commit $@-working $@ + +# Remove all temporary containers +clean: + buildah rm --all diff --git a/.fmsbw/images/msys-activate b/.fmsbw/images/msys-activate new file mode 100644 index 0000000..655fcae --- /dev/null +++ b/.fmsbw/images/msys-activate @@ -0,0 +1,6 @@ +cd /opt/quasi-msys2 +export PATH=`pwd`/gnu-overrides:$PATH +export PKG_CONFIG=pkg-config +set +ex +. env/all.src +set -ex diff --git a/.gitmodules b/.gitmodules index af9fd68..841ce77 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,7 +4,7 @@ ignore = untracked [submodule "scinterm"] path = contrib/scinterm - url = https://github.com/rhaberkorn/scinterm.git + url = https://github.com/orbitalquark/scinterm.git [submodule "lexilla"] path = contrib/lexilla url = https://github.com/ScintillaOrg/lexilla.git @@ -6,6 +6,26 @@ using a prebuilt binary) are included. Entries marked with "(!)" might break macro portability compared to the preceding release. +Version 2.5.1 (2026-01-10) +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* Haiku is officially supported again from now on +* minor documentation improvement for `ED` +* Curses: The command-line uses the hardware cursor by default now. + To re-enable the self-drawn cursor, do something like + `0,2048ED 2#16@ES/SETCARETSTYLE//$ 2048,0ED` +* PDCurses/XCurses (X11): fixed crashes on startup and mouse support + +Regressions introduced by v2.5.0 and now fixed: + +* GTK: Fixed bogus "(Unnamed)" strings in empty message lines +* PDCurses: Fixed reporting of mouse modifiers (CTRL, ALT, SHIFT) +* PDCurses: Fixed colors + (affects the Windows sciteco.exe and gsciteco.exe). +* PDCurses: Fixed hanging after pressing mouse keys + (affects the Windows sciteco.exe and gsciteco.exe). +* PDCurses/WinGUI: Fixed hanging input (affects gsciteco.exe). + Version 2.5.0 (2026-01-01) ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -115,7 +135,7 @@ Version 2.5.0 (2026-01-01) * implemented ^E<code> string building constructs for embedding bytes and codepoints in a strtoul()-like manner * support <:]q> (pop Q-Register) for getting a success/failure boolean - * support <==> and <===> for printing octal and hexadecimal numbers + * (!) support <==> and <===> for printing octal and hexadecimal numbers * support :=/:==/:=== commands: print number without trailing linefeed * Implemented the <^A> command for printing arbitrary strings. You can use :^A to force raw ANSI output. @@ -3,7 +3,7 @@ Installation Instructions Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. -Copyright (C) 2013-2025 Robin Haberkorn +Copyright (C) 2013-2026 Robin Haberkorn Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright @@ -21,13 +21,14 @@ SciTECO Build and Runtime Dependencies * Glib 2 as a cross-platform runtime library (v2.44 or later): https://developer.gnome.org/glib/ * When choosing the Curses interface, you need one of: - * NCurses (http://www.gnu.org/software/ncurses/). - If you plan to use the ncurses MinGW port, - I recommend ncurses 6.0 or later. + * ncurses (http://www.gnu.org/software/ncurses/). + Should be built with wide-character support (--enable-widec). + If you plan to use the ncurses MinGW port, I recommend ncurses 6.0 or later. * NetBSD Curses (https://github.com/sabotage-linux/netbsd-curses). - This is the default on NetBSD. - * PDCursesMod v4.5.1 or later (https://github.com/Bill-Gray/PDCursesMod.git). + This is the default on NetBSD and should always support wide characters. + * PDCursesMod v4.5.4 or later (https://github.com/Bill-Gray/PDCursesMod.git). This is the recommended flavor of PDCurses to use. + It must be built with WIDE=Y and UTF8=Y. * PDCurses/EMCurses (https://github.com/rhaberkorn/emcurses). * PDCurses/XCurses (http://pdcurses.sourceforge.net/). Note that XCurses v3.4 appears to be broken, you may have to @@ -47,7 +48,7 @@ installed by the user manually: * Scintilla (v5.3.0 or later): http://www.scintilla.org/ * When choosing the Curses interface: - * Scinterm (v5.2 or later): + * Scinterm (v5.5 or later): http://foicica.com/scinterm/ * Lexilla (v5.0.0 or later, optional): https://www.scintilla.org/Lexilla.html @@ -75,6 +76,11 @@ On NetBSD: $ sudo pkgin install git gmake pkg-config autoconf automake libtool-base \ glib2 gtk3+ doxygen +On Haiku: + + $ pkgman install git make pkgconfig autoconf automake libtool \ + glib2_devel ncurses6_devel gtk3_devel groff doxygen + Building from Source Tar Ball or Repository =========================================== @@ -2,6 +2,15 @@ News ==== <span class="nf nf-md-new_box"></span> +There is now an official [Haiku port](https://depot.haiku-os.org/#!/pkg/sciteco_curses/) +for the ncurses version, so Haiku users can install SciTECO via the Depot. + +<span class="nf nf-md-new_box"></span> +SciTECO [v2.5.1](https://sciteco.fmsbw.de/downloads/v2.5.1/) has been released. +This is a hotfix release to v2.5.0, which first and foremost fixes the +Windows PDCurses builds. + +<span class="nf nf-md-new_box"></span> SciTECO [v2.5.0](https://sciteco.fmsbw.de/downloads/v2.5.0/) has been released. This release brings many new features, but most importantly makes the language much more usable as a non-interactive scripting language. @@ -23,11 +23,11 @@ The Curses frontend is verified to work with [ncurses](https://www.gnu.org/softw [PDCurses/XCurses](https://github.com/wmcbrine/PDCurses), [PDCursesMod](https://github.com/Bill-Gray/PDCursesMod) and [EMCurses](https://github.com/rhaberkorn/emcurses). -All X/Open-compatible libraries should be supported. +All X/Open-compatible libraries with enhanced and wide-character support should be supported. SVr4 curses without enhanced definitions is **not** supported. Linux, FreeBSD, NetBSD, [Mac OS X](https://sciteco.fmsbw.de/knowledge/Mac%20OS%20Support), -Windows (MinGW 32/64) ~~and [Haiku](https://www.haiku-os.org/) (gcc4)~~ are tested and supported. +Windows (MinGW 32/64) and [Haiku](https://www.haiku-os.org/) (gcc4) are tested and supported. SciTECO compiles with both GCC and Clang. SciTECO should compile just fine on other UNIX-compatible platforms. However UNIX-compatibility is not strictly required: @@ -121,7 +121,9 @@ There are prebuilt binary packages and source bundles for your convenience: * [Main download archive](https://sciteco.fmsbw.de/downloads) * [Download Archive at Sourceforge](https://sourceforge.net/projects/sciteco/files/) * [FreeBSD port](https://www.freshports.org/editors/sciteco/) - [](https://repology.org/project/sciteco-curses/versions) +  +* [Haiku port](https://depot.haiku-os.org/#!/pkg/sciteco_curses) +  * OBS repositories and binary downloads for RPM-based (Fedora, openSUSE, etc.) and Debian-based (Debian, Raspbian, Ubuntu) distributions: [](https://build.opensuse.org/package/show/home:rhaberkorn:sciteco:STABLE/sciteco) @@ -129,12 +131,12 @@ There are prebuilt binary packages and source bundles for your convenience: * [Gtk packages](https://software.opensuse.org/download.html?project=home:rhaberkorn:sciteco:STABLE&package=sciteco-gtk) * [Curses packages](https://software.opensuse.org/download.html?project=home:rhaberkorn:sciteco:STABLE&package=sciteco-curses) * [Arch User Repository](https://aur.archlinux.org/packages/sciteco-git) - [](https://repology.org/project/sciteco/versions) +  * [Alpine Linux package](https://pkgs.alpinelinux.org/package/edge/community/x86_64/sciteco) - [](https://repology.org/project/sciteco/versions) +  * [Chocolatey package](https://community.chocolatey.org/packages/SciTECO) for Windows users - [](https://repology.org/project/sciteco/versions) +  * Yocto/OpenEmbedded users should try the [`sciteco` package from this layer](https://git.fmsbw.de/meta-rhaberkorn/). * Users of OpenWrt may try to install the @@ -2,6 +2,7 @@ Tasks: * Have a look at TECO-86. * VEDIT and PMATE for MS-DOS * Scintilla: upstream 2 patches + * HaikuPorts Known Bugs: * OBS GTK builds sometimes fail: "cannot open display" @@ -28,6 +29,9 @@ Known Bugs: This would be necessary for an interactive screen editing script, that leaves you in <I> always. This would require some refactoring. + * GTK on Haiku: CTRL and AltGr-combinations do not work. + The modifiers are not delivered properly and it appears to affect all Gtk apps + on Haiku. * Gtk: The control characters in tutorial.woman are still styled with the variable-width font since its rendered in STYLE_CONTROLCHAR (36), which is reset in woman.tes. @@ -42,15 +46,6 @@ Known Bugs: In some cases, the internal redrawing blocks SciTECO forever. * @ES/SCI_CLEARALLREPRESENTATIONS// does nothing. Might be a Scintilla bug. - * PDCurses/Wincon does not report button released events. - We try to work around this with click detection, - but it still behaves a bit oddly. - See https://github.com/Bill-Gray/PDCursesMod/issues/330 - Waiting for PDCurses in MSYS to be updated. - * PDCurses/WinGUI: There is still some flickering, but it got better - since key macros update the command line only once. - Could already be fixed upstream, see: - https://github.com/Bill-Gray/PDCursesMod/issues/322 * Win32: Interrupting <EC> will sometimes hang. Affects both PDCurses/WinGUI and Gtk. This no longer happens with ECbash -c 'while true; do true; done'$. @@ -59,15 +54,6 @@ Known Bugs: However the UNIX path translation appears to be a Cygwin feature. If SciTECO would do that, it might break other things (e.g. you might want to refer directory C:\mingw64 instead). - * Win32/Wincon: cat ... | sciteco -i - "Redirection is not supported." - PR: https://github.com/Bill-Gray/PDCursesMod/pull/344 - Waiting for an MSYS package releae. - * PDCurses/Win32: Both Wincon and WinGUI crash when you press *any* - non-ANSI character. This is fixed since PDCurses v4.5.2: - https://github.com/Bill-Gray/PDCursesMod/issues/335 - We're waiting for an MSYS package upgrade. - It could also be worked around by using wget_wch() instead of wgetch(). * PDCurses/Win32: Crashes sometimes without any error message. * NetBSD Curses: scrolling apparently uses hardware idl capabilities resulting in graphical glitches on slow terminals. @@ -801,6 +787,10 @@ Features: * There could be a key macro script for my Russian-phonetic keyboard layout. This would probably require some new key macro states as well. + * Allow the hardware cursor (CARETSTYLE_CURSES) on the main view as well. + We'd have to handle an overlapping info popup, though. + Should we deactivate the hardware cursor via curs_set(0) if it overlaps + the popup? Optimizations: * Use SC_DOCUMENTOPTION_STYLES_NONE in batch mode. diff --git a/configure.ac b/configure.ac index 460862c..673fb33 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.65]) -AC_INIT([SciTECO], [2.5.0], +AC_INIT([SciTECO], [2.5.1], [hackers@fmsbw.de], [sciteco], [https://sciteco.fmsbw.de/]) @@ -215,7 +215,7 @@ case $host in *-*-linux* | *-*-*bsd* | *-*-darwin* | *-*-cygwin* | *-*-haiku*) # NOTE: Keep this on a single line for compatibility # with ancient versions of Autoconf. - AC_CHECK_FUNCS([realpath readlink pathconf fchown dup dup2 getpid open read kill mmap popen pclose isatty fork setsid], , [ + AC_CHECK_FUNCS([realpath readlink pathconf fchown dup dup2 getpid open read kill mmap popen pclose isatty fork execv setsid], , [ AC_MSG_ERROR([Missing libc function]) ]) AC_SEARCH_LIBS(dladdr, [dl], , [ @@ -289,7 +289,8 @@ case $INTERFACE in case $INTERFACE in ncurses) # This gives precendence to the widechar version of ncurses, - # which is necessary for Unicode support even when not using widechar APIs. + # which is necessary for Unicode support and when using more than + # 256 color pairs. # However we also accept libncurses.so if it also contains the # enhanced definitions. # NOTE: This also defines CURSES_CFLAGS and CURSES_LIBS arguments, @@ -303,6 +304,9 @@ case $INTERFACE in CXXFLAGS="$CXXFLAGS $CURSES_CFLAGS" LIBS="$LIBS $CURSES_LIBS" + # Scinterm cares about the correct flags itself. + AC_DEFINE(NCURSES_WIDECHAR, 1, [Provide wide-character functions]) + AC_CHECK_FUNCS([tigetstr]) ;; @@ -312,10 +316,6 @@ case $INTERFACE in # installed, we want this to be an explicit setting. AC_DEFINE(NETBSD_CURSES, 1, [Building against netbsd-curses]) - CFLAGS="$CFLAGS $CURSES_CFLAGS" - CXXFLAGS="$CXXFLAGS $CURSES_CFLAGS" - LIBS="$LIBS $CURSES_LIBS" - if [[ "x$CURSES_LIBS" = "x" ]]; then # libncurses.pc is only shipped by Void Linux' fork, # not in NetBSD itself. @@ -325,9 +325,12 @@ case $INTERFACE in else AC_MSG_CHECKING([checking for netbsd-curses (CURSES_LIBS)]) AC_MSG_RESULT([$CURSES_LIBS]) - LIBS="$LIBS $CURSES_LIBS" fi + CFLAGS="$CFLAGS $CURSES_CFLAGS" + CXXFLAGS="$CXXFLAGS $CURSES_CFLAGS" + LIBS="$LIBS $CURSES_LIBS" + AC_CHECK_FUNCS([tigetstr]) ;; @@ -353,9 +356,11 @@ case $INTERFACE in LIBS="$LIBS $CURSES_LIBS" # It is crucial to define XCURSES before including curses.h. + # This is not important for Scinterm. AC_DEFINE(XCURSES, 1, [Enable PDCurses/XCurses extensions]) AC_CHECK_FUNC([has_mouse], [ + # not important to pass to Scinterm AC_DEFINE(PDC_NCMOUSE, 1, [PDCurses built with ncurses mouse API]) ]) @@ -363,9 +368,6 @@ case $INTERFACE in ;; pdcurses*) - CFLAGS="$CFLAGS $CURSES_CFLAGS" - CXXFLAGS="$CXXFLAGS $CURSES_CFLAGS" - if [[ "x$CURSES_LIBS" = "x" ]]; then AC_CHECK_LIB(pdcurses, PDC_get_version, , [ AC_MSG_ERROR([libpdcurses missing!]) @@ -373,21 +375,26 @@ case $INTERFACE in else AC_MSG_CHECKING([checking for PDCurses (CURSES_LIBS)]) AC_MSG_RESULT([$CURSES_LIBS]) - LIBS="$LIBS $CURSES_LIBS" fi # It is crucial to define PDC_WIDE before including curses.h. # FIXME: MinGW has a pdcurses.h that already defines all necessary macros, # but it's not in upstream PDCurses/PDCursesMod. - AC_CHECK_FUNC([add_wch], [ - AC_DEFINE(PDC_WIDE, 1, [PDCurses built with wide-character support]) - # FIXME: It would be better to check for PDC_FORCE_UTF8. - # Theoretically, we could check for endwin_u[32|64]_4302, - # but I'm not sure this will work reliably in the future. - AC_DEFINE(PDC_FORCE_UTF8, 1, [PDCursesMod forces use of UTF8]) + # FIXME: It would be better to check for PDC_FORCE_UTF8. + # Theoretically, we could check for endwin_u[32|64]_4302, + # but I'm not sure this will work reliably in the future. + CURSES_CFLAGS="$CURSES_CFLAGS -DPDC_WIDE -DPDC_FORCE_UTF8" + + CFLAGS="$CFLAGS $CURSES_CFLAGS" + CXXFLAGS="$CXXFLAGS $CURSES_CFLAGS" + LIBS="$LIBS $CURSES_LIBS" + + AC_CHECK_FUNC([add_wch], [], [ + AC_MSG_ERROR([libpdcurses does not include wide-character support!]) ]) AC_CHECK_FUNC([has_mouse], [ + # not important to pass to Scinterm AC_DEFINE(PDC_NCMOUSE, 1, [PDCurses built with ncurses mouse API]) ]) @@ -458,7 +465,13 @@ AC_ARG_ENABLE(malloc-replacement, [Replace the libc malloc() [default=check]]), [malloc_replacement=$enableval], [malloc_replacement=check]) if [[ $malloc_replacement = check ]]; then - # We currently do not support dlmalloc on Windows and Mac OS. + # malloc() replacement via dlmalloc should work practically everywhere + # but does not extend to shared libraries on Windows and Mac OS. + # That's why it is disabled by default on Windows and Mac OS where other cheap ways + # of introspection are available (see memory.c). + # On the remaining platforms you can try to combine --enable-malloc-replacement + # with --enable-static-executables to link in as many libraries statically + # as possible. case $host in *-*-darwin* | *-mingw*) malloc_replacement=no;; *) malloc_replacement=yes;; diff --git a/contrib/scinterm b/contrib/scinterm -Subproject 53eb713af10abf46f250746a4acc336b16b02f3 +Subproject 7f5b0e2bdfb23a2806ed0cf9c6d25c1f37c0392 diff --git a/debian/changelog b/debian/changelog index 0923f61..ddea47c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +sciteco (2.5.1) unstable; urgency=low + + * new upstream version v2.5.1 + + -- Robin Haberkorn <rhaberkorn@fmsbw.de> Sat, 10 Jan 2026 15:16:39 +0000 + sciteco (2.5.0-0) unstable; urgency=low * new upstream version v2.5.0 diff --git a/doc/cheat-sheet.mm b/doc/cheat-sheet.mm index ba7247c..9a63f4e 100644 --- a/doc/cheat-sheet.mm +++ b/doc/cheat-sheet.mm @@ -825,7 +825,12 @@ Binary negate \fIn\fP \(em negate TECO boolean. . TD . CI "" n = . TD -Show value of \fIn\fP in message line. +Show value of \fIn\fP in message line (decimal). +. TRX +. TD +. CI "" n === +. TD +Show value of \fIn\fP in message line (hexadecimal). . TRX . TD colspan=2 Q-Registers consist of 2 cells: strings and integers. diff --git a/fallback.teco_ini b/fallback.teco_ini Binary files differindex c0b3a49..e1e263b 100644 --- a/fallback.teco_ini +++ b/fallback.teco_ini diff --git a/freebsd/Makefile b/freebsd/Makefile index 1dcd194..e18b7bc 100644 --- a/freebsd/Makefile +++ b/freebsd/Makefile @@ -1,5 +1,5 @@ PORTNAME= sciteco -DISTVERSION= 2.5.0 +DISTVERSION= 2.5.1 CATEGORIES= editors textproc devel MASTER_SITES= https://sciteco.fmsbw.de/downloads/v${DISTVERSION}/ \ SOURCEFORGE/${PORTNAME}/v${DISTVERSION}/ diff --git a/freebsd/distinfo b/freebsd/distinfo index 49a7b48..65d7d37 100644 --- a/freebsd/distinfo +++ b/freebsd/distinfo @@ -1,3 +1,3 @@ -TIMESTAMP = 1745085748 -SHA256 (sciteco-2.4.0.tar.gz) = 5b053644d8365eb0fddd9b268af9d6c6c44786dfa51dd4cbb962abac66670402 -SIZE (sciteco-2.4.0.tar.gz) = 4077220 +TIMESTAMP = 1768082190 +SHA256 (sciteco-2.5.1.tar.gz) = cc99c6855f844f0514f2ed4879bf6a02f11eb489a3b77d88ad7f0bcfe1379fbf +SIZE (sciteco-2.5.1.tar.gz) = 4118025 diff --git a/m4/ax_with_ncurses.m4 b/m4/ax_with_ncurses.m4 index 4dc2f33..cdcfd04 100644 --- a/m4/ax_with_ncurses.m4 +++ b/m4/ax_with_ncurses.m4 @@ -5,8 +5,8 @@ # DESCRIPTION # # This macro checks for an ncurses library with enhanced definitions -# providing a curses.h either in the default search path or as -# established by pkg-config. +# (including wide-char support) providing a curses.h either in the default +# search path or as established by pkg-config. # # It is based on the AX_WITH_CURSES macro but does not attempt # to find any non-standard header, which would require #ifdefing diff --git a/src/cmdline.c b/src/cmdline.c index fa69d91..b944b5e 100644 --- a/src/cmdline.c +++ b/src/cmdline.c @@ -99,6 +99,14 @@ teco_cmdline_init(void) teco_cmdline_ssm(SCI_SETTABDRAWMODE, SCTD_CONTROLCHAR, 0); /* + * FIXME: This works around a problem where the caret is not + * scrolled in multi-line mode after it wraps at the end of the + * line. You cannot scroll the command-line with the mouse, so the + * user won't see any difference. + */ + teco_cmdline_ssm(SCI_SETENDATLASTLINE, FALSE, 0); + + /* * FIXME: Something resets the margin text, so we have to set it last. */ teco_cmdline_ssm(SCI_MARGINSETTEXT, 0, (sptr_t)"*"); @@ -162,12 +170,32 @@ teco_cmdline_insert(const gchar *data, gsize len, GError **error) * Result of command line replacement (}): * Exchange command lines */ + g_clear_error(&tmp_error); + teco_qreg_t *cmdline_reg = teco_qreg_table_find(&teco_qreg_table_globals, "\e", 1); g_auto(teco_string_t) new_cmdline = {NULL, 0}; if (!cmdline_reg->vtable->get_string(cmdline_reg, &new_cmdline.data, &new_cmdline.len, - NULL, error)) + NULL, &tmp_error)) { + teco_error_add_frame_toplevel(); + teco_error_display_short(tmp_error); + g_propagate_error(error, g_steal_pointer(&tmp_error)); + return FALSE; + } + + /* + * SciTECO code must always be UTF-8, but you can smuggle arbitrary bytes + * into the "\e" register. + * This would be cumbersome to test for in teco_state_start_cmdline_pop(). + */ + if (!teco_string_validate_utf8(new_cmdline)) { + g_set_error_literal(&tmp_error, TECO_ERROR, TECO_ERROR_CODEPOINT, + "Invalid UTF-8 byte sequence in command-line replacement"); + teco_error_add_frame_toplevel(); + teco_error_display_short(tmp_error); + g_propagate_error(error, g_steal_pointer(&tmp_error)); return FALSE; + } /* * Search for first differing character in old and @@ -229,7 +257,7 @@ teco_cmdline_insert(const gchar *data, gsize len, GError **error) } } - /* error is handled in teco_cmdline_keypress_c() */ + /* error is handled in teco_cmdline_keypress() */ g_propagate_error(error, g_steal_pointer(&tmp_error)); return FALSE; } diff --git a/src/interface-curses/curses-info-popup.c b/src/interface-curses/curses-info-popup.c index edb6e15..83d4665 100644 --- a/src/interface-curses/curses-info-popup.c +++ b/src/interface-curses/curses-info-popup.c @@ -73,7 +73,7 @@ teco_curses_info_popup_add(teco_curses_info_popup_t *ctx, teco_popup_entry_type_ } static void -teco_curses_info_popup_init_pad(teco_curses_info_popup_t *ctx, attr_t attr) +teco_curses_info_popup_init_pad(teco_curses_info_popup_t *ctx, attr_t attr, gshort pair) { int pad_lines; /**! pad height */ gint pad_cols; /**! entry columns */ @@ -102,11 +102,11 @@ teco_curses_info_popup_init_pad(teco_curses_info_popup_t *ctx, attr_t attr) ctx->pad = newpad(pad_lines, COLS - 2); /* - * NOTE: attr could contain A_REVERSE on monochrome terminals, + * NOTE: attr could contain WA_REVERSE on monochrome terminals, * so we use foreground attributes instead of background attributes. - * This way, we can cancel out the A_REVERSE if necessary. + * This way, we can cancel out the WA_REVERSE if necessary. */ - wattrset(ctx->pad, attr); + wattr_set(ctx->pad, attr, pair, NULL); teco_curses_clrtobot(ctx->pad); /* @@ -161,7 +161,7 @@ teco_curses_info_popup_init_pad(teco_curses_info_popup_t *ctx, attr_t attr) } void -teco_curses_info_popup_show(teco_curses_info_popup_t *ctx, attr_t attr) +teco_curses_info_popup_show(teco_curses_info_popup_t *ctx, attr_t attr, gshort pair) { if (!ctx->length) /* nothing to display */ @@ -171,7 +171,7 @@ teco_curses_info_popup_show(teco_curses_info_popup_t *ctx, attr_t attr) delwin(ctx->window); if (!ctx->pad) - teco_curses_info_popup_init_pad(ctx, attr); + teco_curses_info_popup_init_pad(ctx, attr, pair); gint pad_lines = getmaxy(ctx->pad); /* @@ -183,15 +183,17 @@ teco_curses_info_popup_show(teco_curses_info_popup_t *ctx, attr_t attr) /* window covers message, scintilla and info windows */ ctx->window = newwin(popup_lines, 0, LINES - teco_cmdline.height - popup_lines, 0); - wattrset(ctx->window, attr); + wattr_set(ctx->window, attr, pair, NULL); - wborder(ctx->window, - ACS_VLINE, - ACS_VLINE, /* may be overwritten with scrollbar */ - ACS_HLINE, - ' ', /* no bottom line */ - ACS_ULCORNER, ACS_URCORNER, - ACS_VLINE, ACS_VLINE); + /* + * NOTE: wborder() is broken for large pair numbers, at least on ncurses. + */ + waddch(ctx->window, ACS_ULCORNER); + whline(ctx->window, ACS_HLINE, COLS - 2); + mvwaddch(ctx->window, 0, COLS - 1, ACS_URCORNER); + mvwvline(ctx->window, 1, 0, ACS_VLINE, getmaxy(ctx->window)-1); + /* may be overwritten with scrollbar */ + mvwvline(ctx->window, 1, COLS - 1, ACS_VLINE, getmaxy(ctx->window)-1); copywin(ctx->pad, ctx->window, ctx->pad_first_line, 0, @@ -214,7 +216,7 @@ teco_curses_info_popup_show(teco_curses_info_popup_t *ctx, attr_t attr) * Instead, simply draw reverse blanks. */ wmove(ctx->window, bar_y, COLS-1); - wattrset(ctx->window, attr ^ A_REVERSE); + wattr_set(ctx->window, attr ^ WA_REVERSE, pair, NULL); wvline(ctx->window, ' ', bar_height); } diff --git a/src/interface-curses/curses-info-popup.h b/src/interface-curses/curses-info-popup.h index fd923e9..898ba70 100644 --- a/src/interface-curses/curses-info-popup.h +++ b/src/interface-curses/curses-info-popup.h @@ -49,7 +49,7 @@ teco_curses_info_popup_init(teco_curses_info_popup_t *ctx) void teco_curses_info_popup_add(teco_curses_info_popup_t *ctx, teco_popup_entry_type_t type, const gchar *name, gsize name_len, gboolean highlight); -void teco_curses_info_popup_show(teco_curses_info_popup_t *ctx, attr_t attr); +void teco_curses_info_popup_show(teco_curses_info_popup_t *ctx, attr_t attr, gshort pair); const teco_string_t *teco_curses_info_popup_getentry(teco_curses_info_popup_t *ctx, gint y, gint x); void teco_curses_info_popup_scroll_page(teco_curses_info_popup_t *ctx); void teco_curses_info_popup_scroll(teco_curses_info_popup_t *ctx, gint delta); diff --git a/src/interface-curses/curses-utils.c b/src/interface-curses/curses-utils.c index 875c332..3b25d56 100644 --- a/src/interface-curses/curses-utils.c +++ b/src/interface-curses/curses-utils.c @@ -53,9 +53,9 @@ teco_curses_format_str(WINDOW *win, const gchar *str, gsize len, gint max_width) /* * The entire background might be in reverse, especially * on monochrome terminals. - * In those cases, we have to __remove__ the A_REVERSE flag. + * In those cases, we have to __remove__ the WA_REVERSE flag. */ - attr_t attrs = A_NORMAL; + attr_t attrs = WA_NORMAL; short pair = 0; wattr_get(win, &attrs, &pair, NULL); @@ -81,28 +81,28 @@ teco_curses_format_str(WINDOW *win, const gchar *str, gsize len, gint max_width) chars_added++; if (chars_added > max_width) goto truncate; - wattr_set(win, attrs ^ A_REVERSE, pair, NULL); + wattr_set(win, attrs ^ WA_REVERSE, pair, NULL); waddch(win, '$'); break; case '\r': chars_added += 2; if (chars_added > max_width) goto truncate; - wattr_set(win, attrs ^ A_REVERSE, pair, NULL); + wattr_set(win, attrs ^ WA_REVERSE, pair, NULL); waddstr(win, "CR"); break; case '\n': chars_added += 2; if (chars_added > max_width) goto truncate; - wattr_set(win, attrs ^ A_REVERSE, pair, NULL); + wattr_set(win, attrs ^ WA_REVERSE, pair, NULL); waddstr(win, "LF"); break; case '\t': chars_added += 3; if (chars_added > max_width) goto truncate; - wattr_set(win, attrs ^ A_REVERSE, pair, NULL); + wattr_set(win, attrs ^ WA_REVERSE, pair, NULL); waddstr(win, "TAB"); break; default: @@ -110,7 +110,7 @@ teco_curses_format_str(WINDOW *win, const gchar *str, gsize len, gint max_width) chars_added += 2; if (chars_added > max_width) goto truncate; - wattr_set(win, attrs ^ A_REVERSE, pair, NULL); + wattr_set(win, attrs ^ WA_REVERSE, pair, NULL); waddch(win, '^'); waddch(win, TECO_CTL_ECHO(*str)); } else { @@ -126,7 +126,7 @@ teco_curses_format_str(WINDOW *win, const gchar *str, gsize len, gint max_width) waddnstr(win, str, clen); } } - /* restore original state of A_REVERSE */ + /* restore original state of WA_REVERSE */ wattr_set(win, attrs, pair, NULL); str += clen; diff --git a/src/interface-curses/curses-utils.h b/src/interface-curses/curses-utils.h index 97fc1cc..c6d9d8d 100644 --- a/src/interface-curses/curses-utils.h +++ b/src/interface-curses/curses-utils.h @@ -27,15 +27,12 @@ guint teco_curses_format_str(WINDOW *win, const gchar *str, gsize len, gint max_ guint teco_curses_format_filename(WINDOW *win, const gchar *filename, gint max_width); -/** - * Add Unicode character to window. - * This is just like wadd_wch(), but does not require wide-char APIs. - */ +/** Add Unicode character to window. */ static inline void teco_curses_add_wc(WINDOW *win, gunichar chr) { - gchar buf[6]; - waddnstr(win, buf, g_unichar_to_utf8(chr, buf)); + wchar_t wc = chr; + waddnwstr(win, &wc, 1); } /** diff --git a/src/interface-curses/interface.c b/src/interface-curses/interface.c index 9ace2ee..45821f9 100644 --- a/src/interface-curses/interface.c +++ b/src/interface-curses/interface.c @@ -232,47 +232,19 @@ static struct { * * Scinterm no longer initializes all color pairs for all combinations of * the builtin foreground and background colors. - * Since curses guarantees only 256 color pairs, we cannot do that either. - * Instead we allocate color pairs beginnig at 128 on demand - * (similar to what Scinterm does). - * - * @note Scinterm now also has scintilla_set_color_offsets(), - * so we could use the lower 127 color pairs as well. + * Since curses does not guarantee any number of color pairs, we cannot do that either. + * Instead we allocate color pairs in the first half of + * color pair space on demand, while the second half is reserved to Scinterm. * + * @param attr attributes to modify (for supporting monochrome terminals) * @param fg curses foreground color * @param bg curses background color * @return curses color pair number */ static gshort -teco_color_pair(gshort fg, gshort bg) +teco_color_pair(attr_t *attr, gshort fg, gshort bg) { - static gshort last_pair = 127; - - G_STATIC_ASSERT(sizeof(gshort)*2 <= sizeof(guint)); - gpointer key = GUINT_TO_POINTER(((guint)fg << 16) | bg); - gpointer value = g_hash_table_lookup(teco_interface.pair_table, key); - if (G_LIKELY(value != NULL)) - return GPOINTER_TO_UINT(value); - init_pair(++last_pair, fg, bg); - g_hash_table_insert(teco_interface.pair_table, key, GUINT_TO_POINTER(last_pair)); - return last_pair; -} - -/** - * Curses attribute for the color combination - * according to the color pairs initialized by - * Scinterm. - * This is equivalent to Scinterm's internal term_color_attr(). - * - * @param fg foreground color - * @param bg background color - * @return curses attribute - */ -static inline attr_t -teco_color_attr(gshort fg, gshort bg) -{ - if (has_colors()) - return COLOR_PAIR(teco_color_pair(fg, bg)); + static guint next_pair = 1; /* * Basic support for monochrome terminals: @@ -281,7 +253,29 @@ teco_color_attr(gshort fg, gshort bg) * This will at least work with the terminal.tes and contrast.tes * color schemes. */ - return bg != COLOR_BLACK ? A_REVERSE : 0; + if (!has_colors()) { + if (bg != COLOR_BLACK) + *attr |= WA_REVERSE; + return 0; + } + + G_STATIC_ASSERT(sizeof(gshort)*2 <= sizeof(guint)); + gpointer key = GUINT_TO_POINTER(((guint)fg << 8*sizeof(bg)) | bg); + gpointer value = g_hash_table_lookup(teco_interface.pair_table, key); + if (G_LIKELY(value != NULL)) + return GPOINTER_TO_UINT(value); + if (G_UNLIKELY(next_pair >= COLOR_PAIRS || next_pair > G_MAXSHORT)) + return 0; + init_pair(next_pair, fg, bg); + g_hash_table_insert(teco_interface.pair_table, key, GUINT_TO_POINTER(next_pair)); + return next_pair++; +} + +static inline gint +teco_wattr_set(WINDOW *win, attr_t attr, gshort fg, gshort bg) +{ + gshort pair = teco_color_pair(&attr, fg, bg); + return wattr_set(win, attr, pair, NULL); } /** @@ -395,6 +389,13 @@ teco_view_noutrefresh(teco_view_t *ctx) scintilla_noutrefresh(ctx); } +static inline void +teco_view_update_cursor(teco_view_t *ctx) +{ + if (teco_view_ssm(ctx, SCI_GETCARETSTYLE, 0, 0) & CARETSTYLE_CURSES) + scintilla_update_cursor(ctx); +} + static inline WINDOW * teco_view_get_window(teco_view_t *ctx) { @@ -428,7 +429,7 @@ static void teco_interface_set_window_title(const gchar *title); static void teco_interface_draw_info(void); void -teco_interface_init(void) +teco_interface_init(gint argc, gchar **argv) { for (guint i = 0; i < G_N_ELEMENTS(teco_interface.color_table); i++) teco_interface.color_table[i] = -1; @@ -442,9 +443,13 @@ teco_interface_init(void) teco_cmdline_init(); /* * The default INDIC_STRIKE wouldn't be visible. - * Instead we use INDIC_SQUIGGLE, which is rendered as A_UNDERLINE. + * Instead we use INDIC_SQUIGGLE, which is rendered as WA_UNDERLINE. */ teco_cmdline_ssm(SCI_INDICSETSTYLE, INDICATOR_RUBBEDOUT, INDIC_SQUIGGLE); + /* + * Enable hardware cursor by default. + */ + teco_cmdline_ssm(SCI_SETCARETSTYLE, CARETSTYLE_CURSES, 0); /* * On all platforms except Curses/XTerm, it's @@ -741,6 +746,12 @@ teco_interface_init_interactive(GError **error) teco_interface.pair_table = g_hash_table_new(g_direct_hash, g_direct_equal); start_color(); + /* + * Scinterm uses shorts for color pairs, so G_MAXSHORT is the maximum. + * Some Curses implementations (NetBSD, PDCurses) may support less, + * but set COLOR_PAIRS accordingly. + */ + scintilla_set_color_offsets(0, MIN(COLOR_PAIRS, G_MAXSHORT)/2); /* * On UNIX terminals, the escape key is usually @@ -784,8 +795,6 @@ teco_interface_init_interactive(GError **error) cbreak(); noecho(); - /* Scintilla draws its own cursor */ - curs_set(0); /* * This has also been observed to reduce flickering * in teco_interface_refresh(). @@ -933,7 +942,7 @@ teco_interface_msg_literal(teco_msg_t type, const gchar *str, gsize len) teco_interface_stdio_msg(type, str, len); #endif - short fg, bg; + gshort fg, bg; fg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETBACK, STYLE_DEFAULT, 0)); @@ -955,7 +964,7 @@ teco_interface_msg_literal(teco_msg_t type, const gchar *str, gsize len) } wmove(teco_interface.msg_window, 0, 0); - wattrset(teco_interface.msg_window, teco_color_attr(fg, bg)); + teco_wattr_set(teco_interface.msg_window, 0, fg, bg); teco_curses_format_str(teco_interface.msg_window, str, len, -1); teco_curses_clrtobot(teco_interface.msg_window); } @@ -966,11 +975,11 @@ teco_interface_msg_clear(void) if (!teco_interface.input_pad) /* batch mode */ return; - short fg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETBACK, STYLE_DEFAULT, 0)); - short bg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETFORE, STYLE_DEFAULT, 0)); + gshort fg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETBACK, STYLE_DEFAULT, 0)); + gshort bg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETFORE, STYLE_DEFAULT, 0)); wmove(teco_interface.msg_window, 0, 0); - wattrset(teco_interface.msg_window, teco_color_attr(fg, bg)); + teco_wattr_set(teco_interface.msg_window, 0, fg, bg); teco_curses_clrtobot(teco_interface.msg_window); } @@ -984,10 +993,11 @@ teco_interface_getch(gboolean widechar) /* * Signal that we accept input by drawing a real cursor in the message bar. + * FIXME: curs_set(2) would be better, but isn't always visible. */ wmove(teco_interface.msg_window, 0, 0); - curs_set(1); wrefresh(teco_interface.msg_window); + curs_set(1); gchar buf[4]; gint i = 0; @@ -1014,7 +1024,6 @@ teco_interface_getch(gboolean widechar) i = 0; } while (cp < 0); - curs_set(0); return cp; } @@ -1144,11 +1153,11 @@ teco_interface_draw_info(void) * the current buffer's STYLE_DEFAULT. * The same style is used for MSG_USER messages. */ - short fg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETBACK, STYLE_DEFAULT, 0)); - short bg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETFORE, STYLE_DEFAULT, 0)); + gshort fg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETBACK, STYLE_DEFAULT, 0)); + gshort bg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETFORE, STYLE_DEFAULT, 0)); wmove(teco_interface.info_window, 0, 0); - wattrset(teco_interface.info_window, teco_color_attr(fg, bg)); + teco_wattr_set(teco_interface.info_window, 0, fg, bg); const gchar *info_type_str; @@ -1717,11 +1726,13 @@ teco_interface_popup_show(gsize prefix_len) /* batch mode */ return; - short fg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETFORE, STYLE_CALLTIP, 0)); - short bg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETBACK, STYLE_CALLTIP, 0)); + gshort fg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETFORE, STYLE_CALLTIP, 0)); + gshort bg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETBACK, STYLE_CALLTIP, 0)); teco_interface.popup_prefix_len = prefix_len; - teco_curses_info_popup_show(&teco_interface.popup, teco_color_attr(fg, bg)); + attr_t attr = 0; + gshort pair = teco_color_pair(&attr, fg, bg); + teco_curses_info_popup_show(&teco_interface.popup, attr, pair); } void @@ -1839,7 +1850,31 @@ teco_interface_refresh(gboolean force) wnoutrefresh(teco_interface.msg_window); teco_view_noutrefresh(teco_cmdline.view); teco_curses_info_popup_noutrefresh(&teco_interface.popup); + /* + * If hardware cursors (CARETSTYLE_CURSES) are enabled on the + * command-line view, make sure that the cursor is left + * in the correct position. + * + * FIXME: This shouldn't be necessary if we refreshed the command-line + * view last. Also, if we wanted to support the hardware cursor + * in the main view as well, we'd have to handle a possibly + * overlappig info popup. + */ + teco_view_update_cursor(teco_cmdline.view); doupdate(); + + /* + * Scinterm enables/disables the hardware cursor, + * but only if CARETSTYLE_CURSES is used. + * Disabling the cursor repeatedly ensures you can change + * the caret style interactively. + * It also makes sure the cursor is reset after + * teco_interface_getch(). + * Also, window resizes sometimes enable the hardware cursor on + * PDCurses/wincon (FIXME). + */ + if (!(teco_view_ssm(teco_cmdline.view, SCI_GETCARETSTYLE, 0, 0) & CARETSTYLE_CURSES)) + curs_set(0); } #if NCURSES_MOUSE_VERSION >= 2 @@ -1897,9 +1932,11 @@ teco_interface_process_mevent(MEVENT *event, GError **error) else if (event->bstate & BUTTON_NUM(5)) teco_curses_info_popup_scroll(&teco_interface.popup, +2); - short fg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETFORE, STYLE_CALLTIP, 0)); - short bg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETBACK, STYLE_CALLTIP, 0)); - teco_curses_info_popup_show(&teco_interface.popup, teco_color_attr(fg, bg)); + gshort fg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETFORE, STYLE_CALLTIP, 0)); + gshort bg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETBACK, STYLE_CALLTIP, 0)); + attr_t attr = 0; + gshort pair = teco_color_pair(&attr, fg, bg); + teco_curses_info_popup_show(&teco_interface.popup, attr, pair); return TRUE; } @@ -2115,11 +2152,6 @@ teco_interface_event_loop_iter(void) return; #ifdef KEY_RESIZE case KEY_RESIZE: - /* - * At least on PDCurses/Wincon, the hardware cursor is sometimes - * reactivated. - */ - curs_set(0); teco_interface_resize_all_windows(); break; #endif diff --git a/src/interface-gtk/gtk-info-popup.c b/src/interface-gtk/gtk-info-popup.c index 769f772..f2c8dc8 100644 --- a/src/interface-gtk/gtk-info-popup.c +++ b/src/interface-gtk/gtk-info-popup.c @@ -30,6 +30,8 @@ #include "gtk-label.h" #include "gtk-info-popup.h" +#define TECO_UNNAMED_FILE "(Unnamed)" + /* * FIXME: This is redundant with curses-info-popup.c. */ @@ -336,7 +338,7 @@ teco_gtk_info_popup_idle_add(TecoGtkInfoPopup *self, teco_popup_entry_type_t typ } } - GtkWidget *label = teco_gtk_label_new(name, len); + GtkWidget *label = teco_gtk_label_new(name, len, TECO_UNNAMED_FILE); /* * Gtk v3.20 changed the CSS element names. * Adding a style class eases writing a portable fallback.css. diff --git a/src/interface-gtk/gtk-label.c b/src/interface-gtk/gtk-label.c index 5052cdc..6e05045 100644 --- a/src/interface-gtk/gtk-label.c +++ b/src/interface-gtk/gtk-label.c @@ -32,8 +32,6 @@ #include "gtk-label.h" -#define TECO_UNNAMED_FILE "(Unnamed)" - #define GDK_TO_PANGO_COLOR(X) ((guint16)((X) * G_MAXUINT16)) struct _TecoGtkLabel { @@ -42,8 +40,10 @@ struct _TecoGtkLabel { PangoColor fg, bg; guint16 fg_alpha, bg_alpha; - /** text backing the label or empty string for "(Unnamed)" buffer */ + /** text backing the label or empty string for fallback */ teco_string_t string; + /** fallback string to render if `string` is empty or NULL */ + const gchar *fallback; }; G_DEFINE_TYPE(TecoGtkLabel, teco_gtk_label, GTK_TYPE_LABEL) @@ -125,11 +125,21 @@ teco_gtk_label_class_init(TecoGtkLabelClass *klass) static void teco_gtk_label_init(TecoGtkLabel *self) {} +/** + * Create new TECO label widget. + * + * @param str String to render (can be NULL) + * @param len Length of str or negative value for null-terminated strings. + * @param fallback Null-terminated fallback string to render + * instead of empty strings. + * Must be a string constant with global lifetime or NULL. + */ GtkWidget * -teco_gtk_label_new(const gchar *str, gssize len) +teco_gtk_label_new(const gchar *str, gssize len, const gchar *fallback) { TecoGtkLabel *widget = TECO_GTK_LABEL(g_object_new(TECO_TYPE_GTK_LABEL, NULL)); + widget->fallback = fallback; teco_gtk_label_set_text(widget, str, len); return GTK_WIDGET(widget); @@ -255,8 +265,8 @@ teco_gtk_label_set_text(TecoGtkLabel *self, const gchar *str, gssize len) teco_string_init(&self->string, str, len < 0 ? strlen(str) : len); teco_string_t string = self->string; - if (!string.len) { - string.data = TECO_UNNAMED_FILE; + if (!string.len && self->fallback) { + string.data = (gchar *)self->fallback; string.len = strlen(string.data); } diff --git a/src/interface-gtk/gtk-label.h b/src/interface-gtk/gtk-label.h index ad39c6e..a84608a 100644 --- a/src/interface-gtk/gtk-label.h +++ b/src/interface-gtk/gtk-label.h @@ -24,7 +24,7 @@ #define TECO_TYPE_GTK_LABEL teco_gtk_label_get_type() G_DECLARE_FINAL_TYPE(TecoGtkLabel, teco_gtk_label, TECO, GTK_LABEL, GtkLabel) -GtkWidget *teco_gtk_label_new(const gchar *str, gssize len); +GtkWidget *teco_gtk_label_new(const gchar *str, gssize len, const gchar *fallback); void teco_gtk_label_set_text(TecoGtkLabel *self, const gchar *str, gssize len); teco_string_t teco_gtk_label_get_text(TecoGtkLabel *self); diff --git a/src/interface-gtk/interface.c b/src/interface-gtk/interface.c index 0e1507f..08ccf5d 100644 --- a/src/interface-gtk/interface.c +++ b/src/interface-gtk/interface.c @@ -22,6 +22,7 @@ #include <stdlib.h> #include <string.h> #include <signal.h> +#include <unistd.h> #include <glib.h> #include <glib/gprintf.h> @@ -132,10 +133,10 @@ static struct { } teco_interface; void -teco_interface_init(void) +teco_interface_init(gint argc, gchar **argv) { #ifdef G_OS_UNIX - if (teco_interface.detach) { + if (teco_interface.detach && !g_getenv("__SCITECO_DETACHED")) { /* * NOTE: There is also daemon() on BSD/Linux, * but the following should be more portable. @@ -148,9 +149,29 @@ teco_interface_init(void) setsid(); - g_freopen("/dev/null", "r", stdin); - g_freopen("/dev/null", "a+", stdout); - g_freopen("/dev/null", "a+", stderr); + if (isatty(0)) { + G_GNUC_UNUSED FILE *stdin_new = g_freopen("/dev/null", "r", stdin); + g_assert(stdin_new != NULL); + } + if (isatty(1)) { + G_GNUC_UNUSED FILE *stdout_new = g_freopen("/dev/null", "a+", stdout); + g_assert(stdout_new != NULL); + } + if (isatty(2)) { + G_GNUC_UNUSED FILE *stderr_new = g_freopen("/dev/null", "a+", stderr); + g_assert(stderr_new != NULL); + } + + /* + * gtk_get_option_group() already initialized GTK and even though the + * display is not yet opened, it's unsafe to continue. + * Instead, we re-exec already in the child process. + * We cannot easily remove --detach from argv, but still guard against + * recursive forks by using an environment variable. + */ + g_setenv("__SCITECO_DETACHED", "1", TRUE); + execv(argv[0], argv); + g_assert_not_reached(); } #endif @@ -202,7 +223,7 @@ teco_interface_init(void) */ teco_interface.info_bar_widget = gtk_header_bar_new(); gtk_widget_set_name(teco_interface.info_bar_widget, "sciteco-info-bar"); - teco_interface.info_name_widget = teco_gtk_label_new("", 0); + teco_interface.info_name_widget = teco_gtk_label_new(NULL, 0, NULL); gtk_widget_set_valign(teco_interface.info_name_widget, GTK_ALIGN_CENTER); /* eases writing portable fallback.css that avoids CSS element names */ gtk_style_context_add_class(gtk_widget_get_style_context(teco_interface.info_name_widget), @@ -288,7 +309,7 @@ teco_interface_init(void) gtk_widget_set_name(teco_interface.message_bar_widget, "sciteco-message-bar"); GtkWidget *message_bar_content = gtk_info_bar_get_content_area(GTK_INFO_BAR(teco_interface.message_bar_widget)); - teco_interface.message_widget = teco_gtk_label_new(NULL, 0); + teco_interface.message_widget = teco_gtk_label_new(NULL, 0, NULL); /* eases writing portable fallback.css that avoids CSS element names */ gtk_style_context_add_class(gtk_widget_get_style_context(teco_interface.message_widget), "label"); diff --git a/src/interface.h b/src/interface.h index f196a83..54f807b 100644 --- a/src/interface.h +++ b/src/interface.h @@ -51,7 +51,7 @@ extern teco_view_t *teco_interface_current_view; /** @pure */ -void teco_interface_init(void); +void teco_interface_init(gint argc, gchar **argv); /** @pure */ GOptionGroup *teco_interface_get_options(void); @@ -54,7 +54,7 @@ /* * Define this to pause the program at the beginning - * of main() (Windows only). + * of main(). * This is a useful hack on Windows, where gdbserver * sometimes refuses to start SciTECO but attaches * to a running process just fine. @@ -382,8 +382,7 @@ main(int argc, char **argv) #endif #ifdef DEBUG_PAUSE - /* Windows debugging hack (see above) */ - system("pause"); + getchar(); #endif signal(SIGINT, teco_sigint_handler); @@ -445,7 +444,7 @@ main(int argc, char **argv) */ teco_qreg_table_init(&teco_qreg_table_globals, TRUE); - teco_interface_init(); + teco_interface_init(argc, argv); /* * QRegister view must be initialized only now @@ -1694,11 +1694,7 @@ teco_machine_qregspec_auto_complete(teco_machine_qregspec_t *ctx, teco_string_t /* two-letter Q-Reg */ restrict_len = 2; - /* - * FIXME: This is not quite right as it will propose even - * lower case single or two-letter Q-Register names. - */ - return teco_rb3str_auto_complete(&ctx->result_table->tree, !restrict_len, + return teco_rb3str_auto_complete(&ctx->result_table->tree, TRUE, ctx->name.data, ctx->name.len, restrict_len, insert) && ctx->nesting == 1; } @@ -731,13 +731,18 @@ teco_state_read_file_done(teco_machine_main_t *ctx, teco_string_t str, GError ** return &teco_state_start; sptr_t pos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0); + teco_undo_int(teco_ranges[0].from) = teco_interface_bytes2glyphs(pos); g_autofree gchar *filename = teco_file_expand_path(str.data); /* FIXME: Add wrapper to interface.h? */ if (!teco_view_load(teco_interface_current_view, filename, FALSE, error)) return NULL; - if (teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0) != pos) { + pos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0); + teco_undo_int(teco_ranges[0].to) = teco_interface_bytes2glyphs(pos); + teco_undo_guint(teco_ranges_count) = 1; + + if (teco_ranges[0].from != teco_ranges[0].to) { teco_ring_dirtify(); if (teco_current_doc_must_undo()) diff --git a/src/string-utils.c b/src/string-utils.c index e9dd148..d98b6b0 100644 --- a/src/string-utils.c +++ b/src/string-utils.c @@ -87,8 +87,10 @@ teco_string_get_coord(const gchar *str, gsize off, guint *pos, guint *line, guin } /** - * Get the length of the prefix common to two strings. - * Works with UTF-8 and single-byte encodings. + * Get the length of the prefix common to two UTF-8 strings. + * + * The UTF-8 strings must be validated, which should be the case + * for help labels and short Q-Register names. * * @param a Left string. * @param b Right string. @@ -103,8 +105,8 @@ teco_string_diff(teco_string_t a, const gchar *b, gsize b_len) gsize len = 0; while (len < a.len && len < b_len && - a.data[len] == b[len]) - len++; + g_utf8_get_char(a.data+len) == g_utf8_get_char(b+len)) + len = g_utf8_next_char(b+len) - b; return len; } diff --git a/tests/atlocal.in b/tests/atlocal.in index b2ceda1..81dc1fb 100644 --- a/tests/atlocal.in +++ b/tests/atlocal.in @@ -40,4 +40,4 @@ esac # Default stack size on Linux (8M). # Some platforms allow very large stack sizes, making it hard to test # against potential stack overflows. -ulimit -s 8192 +ulimit -s 8192 || true diff --git a/tests/testsuite.at b/tests/testsuite.at index f34eee3..8145e3d 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -296,6 +296,9 @@ TE_CHECK([[@I/ABCDEF/J @FS/ABC/1234/ ^S+4"N(0/0)']], 0, ignore, ignore) TE_CHECK([[@^Ua/XYZ/ Ga ^S+3"N(0/0)']], 0, ignore, ignore) # NOTE: EN currently inserts another trailing linefeed. TE_CHECK([[@EN/*/XYZ/ ^S+4"N(0/0)']], 0, ignore, ignore) +AT_DATA([test.txt], [[0123456789 +]]) +TE_CHECK([[@ER"test.txt" ^S+11"N(0/0)']], 0, ignore, ignore) AT_CLEANUP AT_SETUP([Editing local registers in macro calls]) @@ -439,6 +442,11 @@ TE_CHECK_CMDLINE([[@^Um{^C^C} Mm]], 0, ignore, stderr) AT_FAIL_IF([! $GREP "^Error:" stderr]) AT_CLEANUP +AT_SETUP([Replace non-Unicode command-line]) +TE_CHECK_CMDLINE([[{0EE 255@I//}]], 0, ignore, stderr) +AT_FAIL_IF([! $GREP "^Error:" stderr]) +AT_CLEANUP + AT_BANNER([Standard library]) AT_SETUP([Option parser]) diff --git a/www/build.tes b/www/build.tes index 848a63c..89ac70a 100755 --- a/www/build.tes +++ b/www/build.tes @@ -18,6 +18,7 @@ <html> <head> <title>SciTECO - <Website> Q[title]</title> + <link rel="canonical" href="https://sciteco.fmsbw.de/Q[file]"> <link rel="icon" type="image/x-icon" href="https://sciteco.fmsbw.de/graphics/sciteco.ico"> <meta name="description" content="Advanced TECO dialect and interactive screen editor based on Scintilla"> <style> @@ -65,7 +66,7 @@ </html> } -EBindex.html HK +[file] EBindex.html HK [title]Home M[header] EClowdown -thtml --html-no-skiphtml --html-no-escapehtml ../NEWS.md I<hr> @@ -73,7 +74,7 @@ EBindex.html HK M[footer] EW -EBscreenshots.html HK +[file]screenshots.html EBN[file] HK [title]Screenshots M[header] EClowdown -thtml --html-no-skiphtml --html-no-escapehtml screenshots.md M[footer] @@ -87,44 +88,44 @@ EW * FIXME: Support out-of-tree builds. * Perhaps pass in the biuld directory. *! -EBQ[builddir]/doc/sciteco.1.html +[file]sciteco.1.html EBN[builddir]/doc/N[file] S<body>S<h1 L 0,.K [title]sciteco(1) M[header] G[grohtml-header] FD<hr>S</body> .,ZK M[footer] -EWsciteco.1.html +EWQ[file] -EBQ[builddir]/doc/sciteco.7.html +[file]sciteco.7.html EBN[builddir]/doc/N[file] S<body>S<h1 L 0,.K [title]sciteco(7) M[header] G[grohtml-header] FD<hr>S</body> .,ZK M[footer] -EWsciteco.7.html +EWQ[file] !* * These grohtml-generated documents are not in the header bar, * but still postprocessed for consinstency. *! -EBQ[builddir]/doc/grosciteco.tes.1.html +[file]grosciteco.tes.1.html EBN[builddir]/doc/N[file] S<body>S<h1 L 0,.K [title]grosciteco.tes(1) M[header] G[grohtml-header] FD<hr>S</body> .,ZK M[footer] -EWgrosciteco.tes.1.html +EWQ[file] -EBQ[builddir]/doc/tedoc.tes.1.html +[file]tedoc.tes.1.html EBN[builddir]/doc/N[file] S<body>S<h1 L 0,.K [title]tedoc.tes(1) M[header] G[grohtml-header] FD<hr>S</body> .,ZK M[footer] -EWtedoc.tes.1.html +EWQ[file] -EBQ[builddir]/doc/tutorial.html +[file]tutorial.html EBN[builddir]/doc/N[file] S<body>S<h1 L 0,.K [title]Tutorial M[header] G[grohtml-header] FD<hr>S</body> .,ZK M[footer] -EWtutorial.html +EWQ[file] EX diff --git a/www/screenshots.md b/www/screenshots.md index df8925a..471374e 100644 --- a/www/screenshots.md +++ b/www/screenshots.md @@ -1,5 +1,9 @@ # Screenshots +## v2.5.1 + + + ## v2.4.0  |
