aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rwxr-xr-x.fmsbw/10-freebsd14-msys-sciteco54
-rwxr-xr-x.fmsbw/20-freebsd14-osx-sciteco7
-rwxr-xr-x.fmsbw/50-ubuntu22-appimage9
-rw-r--r--.fmsbw/images/Makefile67
-rw-r--r--.fmsbw/images/msys-activate6
-rw-r--r--.gitmodules2
-rw-r--r--ChangeLog22
-rw-r--r--INSTALL20
-rw-r--r--NEWS9
-rw-r--r--README14
-rw-r--r--TODO26
-rw-r--r--configure.ac51
m---------contrib/scinterm0
-rw-r--r--debian/changelog6
-rw-r--r--doc/cheat-sheet.mm7
-rw-r--r--fallback.teco_inibin2513 -> 2607 bytes
-rw-r--r--freebsd/Makefile2
-rw-r--r--freebsd/distinfo6
-rw-r--r--m4/ax_with_ncurses.m44
-rw-r--r--src/cmdline.c32
-rw-r--r--src/interface-curses/curses-info-popup.c32
-rw-r--r--src/interface-curses/curses-info-popup.h2
-rw-r--r--src/interface-curses/curses-utils.c16
-rw-r--r--src/interface-curses/curses-utils.h9
-rw-r--r--src/interface-curses/interface.c152
-rw-r--r--src/interface-gtk/gtk-info-popup.c4
-rw-r--r--src/interface-gtk/gtk-label.c22
-rw-r--r--src/interface-gtk/gtk-label.h2
-rw-r--r--src/interface-gtk/interface.c35
-rw-r--r--src/interface.h2
-rw-r--r--src/main.c7
-rw-r--r--src/qreg.c6
-rw-r--r--src/ring.c7
-rw-r--r--src/string-utils.c10
-rw-r--r--tests/atlocal.in2
-rw-r--r--tests/testsuite.at8
-rwxr-xr-xwww/build.tes25
-rw-r--r--www/screenshots.md4
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
diff --git a/ChangeLog b/ChangeLog
index fa3e6c3..f186778 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
diff --git a/INSTALL b/INSTALL
index 5450e6e..3816fde 100644
--- a/INSTALL
+++ b/INSTALL
@@ -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
===========================================
diff --git a/NEWS b/NEWS
index 4382d33..3d7bfe9 100644
--- a/NEWS
+++ b/NEWS
@@ -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.
diff --git a/README b/README
index d110285..4ed071d 100644
--- a/README
+++ b/README
@@ -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/)
- [![FreeBSD port](https://repology.org/badge/version-for-repo/freebsd/sciteco-curses.svg?header=PACKAGE)](https://repology.org/project/sciteco-curses/versions)
+ ![FreeBSD port](https://repology.org/badge/version-for-repo/freebsd/sciteco-curses.svg?header=PACKAGE)
+* [Haiku port](https://depot.haiku-os.org/#!/pkg/sciteco_curses)
+ ![Haiku port](https://repology.org/badge/version-for-repo/haikuports_master/sciteco.svg?header=PACKAGE)
* OBS repositories and binary downloads for RPM-based (Fedora, openSUSE, etc.) and
Debian-based (Debian, Raspbian, Ubuntu) distributions:
[![build result](https://build.opensuse.org/projects/home:rhaberkorn:sciteco:STABLE/packages/sciteco/badge.svg?type=percent)](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)
- [![AUR package](https://repology.org/badge/version-for-repo/aur/sciteco.svg?header=PACKAGE)](https://repology.org/project/sciteco/versions)
+ ![AUR package](https://repology.org/badge/version-for-repo/aur/sciteco.svg?header=PACKAGE)
* [Alpine Linux package](https://pkgs.alpinelinux.org/package/edge/community/x86_64/sciteco)
- [![Alpine Linux Edge package](https://repology.org/badge/version-for-repo/alpine_edge/sciteco.svg?header=PACKAGE)](https://repology.org/project/sciteco/versions)
+ ![Alpine Linux Edge package](https://repology.org/badge/version-for-repo/alpine_edge/sciteco.svg?header=PACKAGE)
* [Chocolatey package](https://community.chocolatey.org/packages/SciTECO)
for Windows users
- [![Chocolatey package](https://repology.org/badge/version-for-repo/chocolatey/sciteco.svg?header=PACKAGE)](https://repology.org/project/sciteco/versions)
+ ![Chocolatey package](https://repology.org/badge/version-for-repo/chocolatey/sciteco.svg?header=PACKAGE)
* 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
diff --git a/TODO b/TODO
index b2f5821..1948f7f 100644
--- a/TODO
+++ b/TODO
@@ -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
index c0b3a49..e1e263b 100644
--- a/fallback.teco_ini
+++ b/fallback.teco_ini
Binary files differ
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);
diff --git a/src/main.c b/src/main.c
index 4d46817..8bc02f1 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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
diff --git a/src/qreg.c b/src/qreg.c
index 4cf92f0..8ef82c0 100644
--- a/src/qreg.c
+++ b/src/qreg.c
@@ -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;
}
diff --git a/src/ring.c b/src/ring.c
index 2445718..5eb16e6 100644
--- a/src/ring.c
+++ b/src/ring.c
@@ -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 - &lt;Website&gt; 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
+
+![Windows 10, new command line](https://sciteco.fmsbw.de/screenshots/v2.5.1-win10-pdcurses.png "Windows 10, new command line")
+
## v2.4.0
![FreeBSD/ncurses, VT240 emulation](https://sciteco.fmsbw.de/screenshots/v2.4.0-freebsd-vt240.png "FreeBSD/ncurses, VT240 emulation")