diff options
| -rw-r--r-- | .gitmodules | 2 | ||||
| -rw-r--r-- | ChangeLog | 51 | ||||
| -rw-r--r-- | NEWS | 16 | ||||
| -rw-r--r-- | TODO | 141 | ||||
| -rw-r--r-- | configure.ac | 4 | ||||
| m--------- | contrib/scinterm | 0 | ||||
| m--------- | contrib/scintilla | 0 | ||||
| -rw-r--r-- | debian/changelog | 6 | ||||
| -rw-r--r-- | doc/sciteco.1.in | 11 | ||||
| -rw-r--r-- | doc/tutorial.ms.in | 4 | ||||
| -rw-r--r-- | fallback.teco_ini | bin | 2607 -> 2640 bytes | |||
| -rw-r--r-- | freebsd/Makefile | 2 | ||||
| -rw-r--r-- | freebsd/distinfo | 6 | ||||
| -rw-r--r-- | freebsd/pkg-plist | 1 | ||||
| -rw-r--r-- | lib/Makefile.am | 2 | ||||
| -rw-r--r-- | lib/colors/solarized.tes | 53 | ||||
| -rw-r--r-- | lib/colors/terminal.tes | 1 | ||||
| -rw-r--r-- | lib/fnkeys.tes | bin | 4391 -> 5102 bytes | |||
| -rw-r--r-- | lib/opener.tes | 15 | ||||
| -rw-r--r-- | lib/tank.tes | 211 | ||||
| -rw-r--r-- | src/core-commands.c | 126 | ||||
| -rw-r--r-- | src/interface-curses/interface.c | 385 | ||||
| -rw-r--r-- | src/interface-gtk/interface.c | 93 | ||||
| -rw-r--r-- | src/interface.h | 7 | ||||
| -rw-r--r-- | src/main.c | 24 | ||||
| -rw-r--r-- | src/ring.c | 12 | ||||
| -rw-r--r-- | src/sciteco.h | 6 | ||||
| -rw-r--r-- | src/spawn.c | 2 | ||||
| -rw-r--r-- | src/stdio-commands.c | 37 | ||||
| -rw-r--r-- | src/view.c | 12 | ||||
| -rw-r--r-- | tests/testsuite.at | 17 | ||||
| -rwxr-xr-x | www/build.tes | 25 |
32 files changed, 814 insertions, 458 deletions
diff --git a/.gitmodules b/.gitmodules index 841ce77..af9fd68 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,7 +4,7 @@ ignore = untracked [submodule "scinterm"] path = contrib/scinterm - url = https://github.com/orbitalquark/scinterm.git + url = https://github.com/rhaberkorn/scinterm.git [submodule "lexilla"] path = contrib/lexilla url = https://github.com/ScintillaOrg/lexilla.git @@ -6,6 +6,57 @@ using a prebuilt binary) are included. Entries marked with "(!)" might break macro portability compared to the preceding release. +Version 2.5.2 (2026-04-20) +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* sped up `EQq<filename>$` +* Curses/UNIX: It should be possible to interrupt more potentially blocking + operations with CTRL+C (SIGINT). +* `^A` is no longer executed in parse-only mode - fixes bogus warnings. + Has been broken since v2.5.0. +* (!) `^A` now supports a message severity level, so you can log + warnings and errors as well. +* Added TANK MODE. + Launch with EI^EQ[$SCITECOPATH]/tank.tes$ +* support Groff v1.24.0 and later +* fnkeys.tes: When preserving the horizontal column, + take the character representations and tab draw modes into account. +* SIGTERM/SIGHUP always quits. + On GTK recovery files are always dumped first. +* decreased default recovery dumping interval to 120s +* (!) `-$$` and `-^C` always return -1 now instead of passing down the prefix sign +* fixed scrolling at the end of a multi-line command-line +* fixed auto completion of two-character Q-register names +* `ER` updates `^S`/`^Y` now as any other text insertion +* GTK: fixed --detach and support stdout/stderr redirections. + Has been broken since v2.5.0. +* GTK: Fixed interaction between `^T` and main input handling. + Key presses are no longer missed and inserted into the command line later. +* Curses: handle window resizes when blocking in `^T` and don't return function keys. + Also, filter out bogus key press events on PDCursesMod/WinGUI. +* Curses: fixed monochrome support. + Has been broken since v2.5.0. +* Curses: fixed 16-color schemes and default colors (`sciteco --no-profile`) + on 8-color terminals (like the Linux/FreeBSD VTs) + Has been broken since v2.5.0. +* Curses: default colors are now closer to terminal.tes +* Curses: fixed colors on emulators with less than 256 color pairs + (e.g. TERM=rxvt) +* Curses: support up to 32767 color pairs +* Curses: require wide-char support even on PDCurses +* fixed auto-completion of Unicode (non-ANSI) file names +* disallow replacing non-Unicode command lines via `{` and `}` +* Curses: fixed flickering of the hardware cursor on the command line. + On the downside, this can result in the cursor being visible when + drawing the buffer as well. + Has been broken since v2.5.1. +* fallback.teco_ini: added commented-out line to disable the hardware cursor +* fallback.teco_ini: fixed exclusion of the unnamed buffer from custom + margin and indention settings. + Has been broken since v2.5.0. +* opener.tes: opener.check-recovery can be used in ~/.teco_ini to check + for and warn about the presence of `#recovery#` files. + Version 2.5.1 (2026-01-10) ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2,17 +2,5 @@ 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. -Also, the command-line is syntax highlighted now and recovery files are written -to help you recover from crashes and other unexpected terminations. +SciTECO [v2.5.2](https://sciteco.fmsbw.de/downloads/v2.5.2/) has been released. +This is mostly a fixup to v2.5.1 and v2.5.0. @@ -1,8 +1,7 @@ Tasks: * Have a look at TECO-86. * VEDIT and PMATE for MS-DOS - * Scintilla: upstream 2 patches - * HaikuPorts + * Make sure that fmsbw.de is indexed by Google Known Bugs: * OBS GTK builds sometimes fail: "cannot open display" @@ -10,24 +9,16 @@ Known Bugs: * In multiline command lines, the asterisk can scroll out of view. Perhaps it has to be drawn independently of Scinterm. * FreeBSD's `crontab -e` is not compatible with SciTECO's savepoint mechanism. - * ncurses: GNOME Terminal and Xterm produces BUTTON3_PRESSED (without BUTTON3_RELEASED) - events when scrolling horizontally. - This is fixed upstream in ncurses and there is a workaround for - older ncurses versions which limits the effects of this bug. - * ncurses: st and Xterm produce BUTTON2_RELEASED, followed by BUTTON2_PRESSED - when clicking the middle button. - We also *sometimes* get it in the correct order. - This bug has been fixed upstream and there is a workaround for - older ncurses versions. You may loose the distinction between - pressed and release events, though. + * Gnome Terminal: You can see hardware cursor flickering when deleting + lines repeatedly (if it's enabled of course). This is also visible in Aerc. + Scroll regions are already used, but only when scrolling. + Disabling the hardware cursor around doupdate() causes flickering + of the cursor on some terminals. * Upgrade to Scintilla 5.5.7 requires charconv header which bumps the minimum GCC version to 8.1 (officially 9). This breaks OpenSUSE 15.5-15.6 builds. * Build problems on Fedora 41: See mail from Blake McBride. - * @^Um{-$$} Mm= should probably return -1. * {@I/$$23=/} doesn't insert anything after $$. - 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 @@ -36,16 +27,18 @@ Known Bugs: the variable-width font since its rendered in STYLE_CONTROLCHAR (36), which is reset in woman.tes. Perhaps it should always be in lexer.font. - * The current horizontal position (set by 4EJ via SCI_GETCOLUMN) is - often wrong, i.e. pressing the up-cursor key can get you into the - wrong column. - Character representations obviously take always one column. - This would have to be fixed in Scintilla's SCI_GETCOLUMN. * Excessively long lines slow down SciTECO too much, especially when enabling SCI_SETWRAPMODE(SC_WRAP_CHAR). In some cases, the internal redrawing blocks SciTECO forever. * @ES/SCI_CLEARALLREPRESENTATIONS// does nothing. Might be a Scintilla bug. + * Some operations can be hard to interrupt because they result + in costly calculations within Scintilla. + For instance interrupting ECcat /dev/zero$ can hang in + the Scintilla Undo operation. + This particular hang could be avoided by getting rid of + Scintilla undo actions in teco_view_load_from_channel() and spawn.c. + We can probably only get rid of undo actions completely and globally. * Win32: Interrupting <EC> will sometimes hang. Affects both PDCurses/WinGUI and Gtk. This no longer happens with ECbash -c 'while true; do true; done'$. @@ -56,17 +49,21 @@ Known Bugs: want to refer directory C:\mingw64 instead). * PDCurses/Win32: Crashes sometimes without any error message. * NetBSD Curses: scrolling apparently uses hardware idl capabilities - resulting in graphical glitches on slow terminals. + without scroll regions resulting in graphical glitches on slow terminals. idlok(FALSE) is apparently ignored. - * NetBSD: Very slow, even the redrawing. + * NetBSD Curses: Very slow, even the redrawing. This does not happen with ncurses on NetBSD. + Do they have immedok(TRUE) enabled by default? * dlmalloc's malloc_trim() does not seem to free any resident memory after hitting the OOM limit, eg. after <%a>. Apparently an effect of HAVE_MORECORE (sbrk()) - some allocation is always left at the end. * S<LF>^ES^N<$ does not find the first line that does not begin with "<". This is because \s+ backtracks and can match shorter sequences. - Perhaps ^ES should always be translated to \s++ (possessive quantifier)? + TECO-11 patterns do not backtrack apparently. + Perhaps ^ES should always be translated to \s++ (possessive quantifier). + On the other hand, we would have to extend the pattern syntax to allow + backtracking. * Colors are still wrong in Linux console even if TERM=linux-16color when using Solarized. Affects e.g. the message line which uses the reverse of STYLE_DEFAULT. @@ -91,6 +88,7 @@ Known Bugs: re2 should be an optional dependency, so we can still build against the glib APIs. Optionally, I could build a PCRE-compatible wrapper for Rust's regex crate. + It would also be possible to port hxrex to UTF-8 and add it as a submodule. * It is still possible to crash SciTECO using recursive functions, since they map to the C program's call stack. It is perhaps best to use another stack of @@ -201,6 +199,27 @@ Known Bugs: Also, the command-line redrawing is still broken in GNOME Terminal. * When config.status is run as a consequence of touching configure.ac, config.h will be wrong, forcing us to rerun ./configure. + * Does not scroll at the end of a multiline command-line + (the first character on a scrolled line will not be visible). + On Curses the hardware cursor will still stay at the end of the window of course. + Obviously a Scintilla bug. + Break on EditView::DisplayFromPosition + Perhaps the problem is in Editor::MaxScrollPos(). + As a workaround, we set SCI_SETENDATLASTLINE(0). + * OBS builds do not provide Ubuntu i586 since subversion is obviously no longer + packaged, breaking obs-service-tar-scm. + Is there any third-party build? + * GTK: too much flickering in tank mode when shooting. + This is because my font doesn't contain the correct glyph. + Try: I ^E<10041>$ + Perhaps we should use more widespread glyphs. + https://groups.google.com/g/scintilla-interest/c/ZgLik8tNyjM + * There are still potentially blocking syscalls that could result in + SciTECO hanging. Curses/UNIX can rely on SIGINT, but this won't + help on any other platform. + All blocking operations must be within an event loop and call into + teco_interface_is_interrupted() to potentially drive the UI and + detect CTRL+C presses. Features: * Should we support *.sgml files with the HTML lexer? @@ -221,6 +240,7 @@ Features: Would probably require some kind of server... * opener.tes should try to center the opened line (SCI_SETFIRSTVISIBLELINE). + However, this would require a new ED hook, so we can query SCI_LINESONSCREEN. * Rubout of SCI_GOTOPOS could also restore the vertical scrolling position (SCI_SETFIRSTVISIBLELINE). So e.g. rubbing out ZJ restores the exact view. @@ -298,21 +318,11 @@ Features: line. May be useful e.g. for solarized's F5 key (i.e. function key macros that need to terminate the command line as they cannot be rubbed out properly). - * Key macros could support special escape sequences - that allow us to modify the parser state reliably. - E.g. one construct could expand to the current string argument's - termination character (which may not be Escape). - In combination with a special key macro state - effective only in the start state of the string building - state machine, perhaps only in insertion commands, this - could be used to make the cursor movement keys work in - insertion commands by automatically terminating the command. - Even more simple, the function key flag could be effective - only when the termination character is $. - Instead of reserving a character, we could also reserverve - a bit in the function key maks. - It's however impossible to reliably return to the start state - from arbitrary parser states. + * Key macro flag to automatically terminate insertion commands + (or everywhere where it's safe). + Should be used to make the cursor movement keys (fnkeys.tes) + automatically terminate string arguments. + Will probably require a new state callback. * Support more function keys. We can define more function keys via define_key(3NCURSES). Unfortunately they are not really standardized - st and urxvt for instance @@ -389,7 +399,6 @@ Features: * ^A currently doesn't flush the output. Perhaps flushing should be controlled by the language. Perhaps via the ET flags. - * Mini game where you can drive a tank around your source code. * `@]q` to pop keeping the numeric part of q intact. Perhaps `@@]q` to overwrite __only__ the numeric part, but keeping the string intact. @@ -480,7 +489,12 @@ Features: command-line termination. Also, we'd need a command to fetch the modification timestamp as well. - * Recovery files should probably be hidden during auto completions. + * Curses: Dump recovery files on SIGTERM and SIGHUP as well. + Useful when we are unexpectedly but gracefully terminated, + Could only be done on Curses by setting a small timeout and + returning from getch() frequently to check whether the signal + ocurred. + On Wincon we could also react to window closes. * Error handling in SciTECO macros: Allow throwing errors with e.g. [n]^F<description>^F where n is an error code, defaulting to 0 and description is the error string - there could be code-specific @@ -593,6 +607,7 @@ Features: * It should be possible to disable auto-completions of one-character register names, so that we can map the idention macro to M<TAB>. * Add a configure-switch for LTO (--enable-lto). + All of the packages will have to be adapted as well. * There should be a string building construct for escaping search patterns. Since string building is performed immediately before @@ -600,9 +615,12 @@ Features: search for a Q-Register verbatim. * Tweak the Makefile lexer for Automake support. In the simplest case, just add the *.am file extension. - * Add an fnkeys.tes alternative where moving cursor keys + * Add key macros where moving cursor keys leaves you in the insert (I) command. That will behave very similar to classical editors. + See n00b.tes. + This still requires an ED hook for new command lines and + FQ to remove Q-registers. * Lexing via SciTECO macros? They would have to be in their own parser instance since Scintilla could ask us to restyle at any time and within string arguments, @@ -699,6 +717,9 @@ Features: ^U[^L0]SciTECO ^XI <^XT> ^XF$ As a first step, customizing the window title might be the most useful, as often, you don't need the "SciTECO - <Buffer>" prefix. + * Would also allow the configuration of "powerline" symbols at least + for the Curses variant. + https://github.com/ryanoasis/powerline-extra-symbols * Until we have customizeable layouts, it may make sense to hardcode the current line+column in to the message line. * With Unicode icon support, we might want to replace a few more @@ -748,14 +769,6 @@ Features: To format a hex byte, you would write 16^R 2,Qa\ ^D. The same extension might not be desirable for =/==/===, unless they are colon-modified?. - * Curses: allow freely using RGB colors instead of only the constants - corresponding with the 16 default curses colors. - Scinterm v5.5 supports that. This means we also need a hash map for - mapping RGB color values to curses color numbers, analoguous to what - Scinterm does. - The problem of Scinterm reusing the same color namespace both for - arbitrary RGB values and for predefined special constants however - hasn't been solved yet. * Scinterm: INDIC_PLAIN and INDIC_STRIKE could theoretically be supported. PDCurses has A_STRIKETHROUGH. This would require Scintilla API changes, though, as it currently calls SurfaceImpl::FillRectangle(), @@ -791,6 +804,36 @@ Features: 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? + * ncurses: Support default colors (use_default_colors()). + Instead of drawing a black background and white foreground + we could use pair number -1. + This means you don't suddenly become white-on-black on terminals + that use black-on-white by default. + On the other hand, not all color schemes might look good, + so this would have to be a setting (ED flag). + Also, Scinterm would have to support it as well. + This also appears to be responsible for the greyish background + on Haiku and GNOME Terminal: They don't have a true black as color 0 + even if the default terminal background is a true black. + * Ctags support + Perhaps can be Video TECO compatible. + https://github.com/universal-ctags/ctags + * Non-spacing code points would currently be handled as separate + SciTECO characters. + On the one hand, this means you can remove accents from characters. + On the other hand, it may be inconvinient in texts with many accents. + What do Asian scripts like Hangul do? + * :^Q should perhaps return a status code, so you can check for + invalid line ranges. + The current :^Q (dot to line) would have to be renamed to + something else, like ^L. + Or alternatively @^Q could simply ignore out of range + arguments. + * Perhaps add math.tes with primitives from my Project Euler + solutions to the standard library. + * :^W should perhaps inhibit the caret scrolling. + When using ^W purely as a wait command, this could be undesirable. + Also, it is undesirable for some animations (e.g. shooting in tank.tes). Optimizations: * Use SC_DOCUMENTOPTION_STYLES_NONE in batch mode. diff --git a/configure.ac b/configure.ac index 673fb33..f64636b 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.1], +AC_INIT([SciTECO], [2.5.2], [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 execv setsid], , [ + AC_CHECK_FUNCS([realpath readlink pathconf fchown dup dup2 getpid open read kill mmap popen pclose isatty fork execv setsid sigaction], , [ AC_MSG_ERROR([Missing libc function]) ]) AC_SEARCH_LIBS(dladdr, [dl], , [ diff --git a/contrib/scinterm b/contrib/scinterm -Subproject 7f5b0e2bdfb23a2806ed0cf9c6d25c1f37c0392 +Subproject 274656ad8fd7478ff7ed7fc4e04eedb7863b2f9 diff --git a/contrib/scintilla b/contrib/scintilla -Subproject b64652b857d3a5922c72ccc801ac77aa9cff27c +Subproject 748f9cbc4f2a9d7a4216feaa37aee8e834123f0 diff --git a/debian/changelog b/debian/changelog index ddea47c..ab0d425 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +sciteco (2.5.2) unstable; urgency=low + + * new upstream version v2.5.2 + + -- Robin Haberkorn <rhaberkorn@fmsbw.de> Sun, 19 Apr 2026 20:21:14 +0000 + sciteco (2.5.1) unstable; urgency=low * new upstream version v2.5.1 diff --git a/doc/sciteco.1.in b/doc/sciteco.1.in index e47ca93..83dba44 100644 --- a/doc/sciteco.1.in +++ b/doc/sciteco.1.in @@ -425,13 +425,12 @@ Note that this signal can usually also be generated when pressing .TP .SCITECO_TOPIC "SIGTERM" .B SIGTERM +.TQ +.SCITECO_TOPIC "SIGHUP" +.B SIGHUP Try to gracefully shut down \*(ST. -In batch mode this only interrupts the currently running macro -similar to \fBSIGINT\fP causing \*(ST to exit. -If technically possible, user interfaces will additionally -process \fBSIGTERM\fP in interactive mode as if the \fICLOSE\fP -function key has been pressed, which will result in unconditional -program termination or user-programmed behaviour. +If technically possible, this will immediately dump recovery +files unless recovery file dumping is disabled (\(lq0,6EJ\(rq). . . .SH FILES diff --git a/doc/tutorial.ms.in b/doc/tutorial.ms.in index 92da0af..4016605 100644 --- a/doc/tutorial.ms.in +++ b/doc/tutorial.ms.in @@ -36,6 +36,10 @@ . ns .. . +.\" Work around problems with early device extension commands. +.\" See groff(7) and https://savannah.gnu.org/bugs/?67992 +\c +. .\" The entire document is monospaced as users are supposed to .\" navigate through it and perhaps even modify it inplace. .SCITECO_TT diff --git a/fallback.teco_ini b/fallback.teco_ini Binary files differindex e1e263b..bd92c29 100644 --- a/fallback.teco_ini +++ b/fallback.teco_ini diff --git a/freebsd/Makefile b/freebsd/Makefile index e18b7bc..8550f5a 100644 --- a/freebsd/Makefile +++ b/freebsd/Makefile @@ -1,5 +1,5 @@ PORTNAME= sciteco -DISTVERSION= 2.5.1 +DISTVERSION= 2.5.2 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 65d7d37..9396b55 100644 --- a/freebsd/distinfo +++ b/freebsd/distinfo @@ -1,3 +1,3 @@ -TIMESTAMP = 1768082190 -SHA256 (sciteco-2.5.1.tar.gz) = cc99c6855f844f0514f2ed4879bf6a02f11eb489a3b77d88ad7f0bcfe1379fbf -SIZE (sciteco-2.5.1.tar.gz) = 4118025 +TIMESTAMP = 1776638070 +SHA256 (sciteco-2.5.2.tar.gz) = 94149fa3371e3adff723ae933502b5983804c4e06a681c6d00b0af19c439a978 +SIZE (sciteco-2.5.2.tar.gz) = 4113973 diff --git a/freebsd/pkg-plist b/freebsd/pkg-plist index ab74145..dd3e7cb 100644 --- a/freebsd/pkg-plist +++ b/freebsd/pkg-plist @@ -13,6 +13,7 @@ share/man/man7/%%PROGRAM_PREFIX%%sciteco.7.gz %%DATADIR%%/lib/getopt.tes %%DATADIR%%/lib/lexer.tes %%DATADIR%%/lib/repl.tes +%%DATADIR%%/lib/tank.tes %%DATADIR%%/lib/tecat.tes %%LEXILLA%%%%DATADIR%%/lib/lexers/abaqus.tes %%LEXILLA%%%%DATADIR%%/lib/lexers/ada.tes diff --git a/lib/Makefile.am b/lib/Makefile.am index 0da616a..04e83ad 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,5 +1,5 @@ dist_scitecolib_DATA = color.tes lexer.tes session.tes opener.tes \ - fnkeys.tes string.tes getopt.tes + fnkeys.tes string.tes getopt.tes tank.tes # Standalone scripts. # These are not installed via _SCRIPTS as it would add the --program-prefix. diff --git a/lib/colors/solarized.tes b/lib/colors/solarized.tes index 11567d9..91b2718 100644 --- a/lib/colors/solarized.tes +++ b/lib/colors/solarized.tes @@ -17,41 +17,24 @@ * `solarized.toggle` will be mapped to the F5 function key. * F5 will also automatically terminate the command line. *! -0EJ-1"= - 000,043,054:M[color.rgb],08,3EJ Q[color.lblack] U[color.base03] - 007,054,066:M[color.rgb],00,3EJ Q[color.black] U[color.base02] - 088,110,117:M[color.rgb],10,3EJ Q[color.lgreen] U[color.base01] - 101,123,131:M[color.rgb],11,3EJ Q[color.lyellow] U[color.base00] - 131,148,150:M[color.rgb],12,3EJ Q[color.lblue] U[color.base0] - 147,161,161:M[color.rgb],14,3EJ Q[color.lcyan] U[color.base1] - 238,232,213:M[color.rgb],07,3EJ Q[color.white] U[color.base2] - 253,246,227:M[color.rgb],15,3EJ Q[color.lwhite] U[color.base3] - 181,137,000:M[color.rgb],03,3EJ !* yellow *! - 203,075,022:M[color.rgb],09,3EJ Q[color.lred] U[color.orange] - 220,050,047:M[color.rgb],01,3EJ !* red *! - 211,054,130:M[color.rgb],05,3EJ !* magenta *! - 108,113,196:M[color.rgb],13,3EJ Q[color.lmagenta]U[color.violet] - 038,139,210:M[color.rgb],04,3EJ !* blue *! - 042,161,152:M[color.rgb],06,3EJ !* cyan *! - 133,153,000:M[color.rgb],02,3EJ !* green *! -| - 000,043,054:M[color.rgb]U[color.base03] - 007,054,066:M[color.rgb]U[color.base02] - 088,110,117:M[color.rgb]U[color.base01] - 101,123,131:M[color.rgb]U[color.base00] - 131,148,150:M[color.rgb]U[color.base0] - 147,161,161:M[color.rgb]U[color.base1] - 238,232,213:M[color.rgb]U[color.base2] - 253,246,227:M[color.rgb]U[color.base3] - 181,137,000:M[color.rgb]U[color.yellow] - 203,075,022:M[color.rgb]U[color.orange] - 220,050,047:M[color.rgb]U[color.red] - 211,054,130:M[color.rgb]U[color.magenta] - 108,113,196:M[color.rgb]U[color.violet] - 038,139,210:M[color.rgb]U[color.blue] - 042,161,152:M[color.rgb]U[color.cyan] - 133,153,000:M[color.rgb]U[color.green] -' +0,3EJ + +000,043,054:M[color.rgb]U[color.base03] +007,054,066:M[color.rgb]U[color.base02] +088,110,117:M[color.rgb]U[color.base01] +101,123,131:M[color.rgb]U[color.base00] +131,148,150:M[color.rgb]U[color.base0] +147,161,161:M[color.rgb]U[color.base1] +238,232,213:M[color.rgb]U[color.base2] +253,246,227:M[color.rgb]U[color.base3] +181,137,000:M[color.rgb]U[color.yellow] +203,075,022:M[color.rgb]U[color.orange] +220,050,047:M[color.rgb]U[color.red] +211,054,130:M[color.rgb]U[color.magenta] +108,113,196:M[color.rgb]U[color.violet] +038,139,210:M[color.rgb]U[color.blue] +042,161,152:M[color.rgb]U[color.cyan] +133,153,000:M[color.rgb]U[color.green] :Q[solarized.light]"< 0U[solarized.light] ' @[solarized.light]{ diff --git a/lib/colors/terminal.tes b/lib/colors/terminal.tes index ea048aa..39c5bac 100644 --- a/lib/colors/terminal.tes +++ b/lib/colors/terminal.tes @@ -9,6 +9,7 @@ Q[color.white]U[color.selback] !* Also used for popups *! [color.calltip] 0,Q[color.lwhite],Q[color.black] +!* Due to the bold attribute this should be grey even on 8-color terminals *! [color.comment] 1,Q[color.black],Q[color.lblack] [color.number] 0,Q[color.black],Q[color.cyan] [color.keyword] 1,Q[color.black],Q[color.lwhite] diff --git a/lib/fnkeys.tes b/lib/fnkeys.tes Binary files differindex 937caf9..f58a26a 100644 --- a/lib/fnkeys.tes +++ b/lib/fnkeys.tes diff --git a/lib/opener.tes b/lib/opener.tes index c0183c8..8bcd896 100644 --- a/lib/opener.tes +++ b/lib/opener.tes @@ -36,3 +36,18 @@ EBN[\.i] Q.c-1,Q.l-1ESFINDCOLUMN:J > ]* } + +!*$ + * M[opener.check-recovery] -- Warn if there if a recovery file (#filename#) is detected + * + * This points to a prior crash or unexpected termination. + *! +@[opener.check-recovery]{ + :Q*"= ' + [* + EQ.f G* I# R + <-A"I 1; ' :R;> + I# + 1:EN*Q.f"S 2Detected recovery file "Q.f" ' + ]* +} diff --git a/lib/tank.tes b/lib/tank.tes new file mode 100644 index 0000000..0894009 --- /dev/null +++ b/lib/tank.tes @@ -0,0 +1,211 @@ +!* + * TANK MODE + * + * Drive an ASCII tank around your buffer. + * Invoke via EIQ[$SCITECOPATH]/tank.tes + *! +[tank.sprite.0] !* background *! + +!* FIXME: Perhaps encode the gun's top in the integer cell *! +[tank.sprite.1] +█▓█▓ +╠════○ +▓█▓█ +[tank.sprite.2] + █▓█▓ +○════╣ + ▓█▓█ +[tank.sprite.3] + ┌┐ +▓││█ +█││▓ +▓┴┴█ +[tank.sprite.4] +█┬┬▓ +▓││█ +█││▓ + └┘ + +!* + * f,tM[tank.rand] - LCG pseudo random number generator for values between f and t + * This is based on the version in the BSD libc. + *! +::U[tank.rand] +@[tank.rand]{ + U.tU.f + (1103515245*Q[tank.rand]+12345) & (2^*31-1)U[tank.rand] + (Q[tank.rand]^/(Q.t-Q.f+1)+Q.f) +} + +!* x,yM[tank.goto] -> success|failure *! +@[tank.goto]{ + U.yU.x + Q.x"< 0 ' Q.y"< 0 ' + J Q.y:L"F 0 ' + Q.x<0A"< I F> ' 0A-10"= I F> ' C> + -1 +} + +!* x,y,spriteM[tank.blit] *! +@[tank.blit]{ + U.sU.yU.x Q.xU.#x0 + Q.s"N + 10[tank.sprite.0] !* background *! + %[tank.blit] + ' + < + %.iQ[tank.sprite.\.s]U.c Q.c:; + Q[tank.blit]&1"= + !* toggle the chain character to simulate movements *! + Q.c-█"= ▓U.c | Q.c-▓"= █U.c ' ' + ' + + Q.c-10"= + %.y Q.#x0U.x + Q.s"N 10:[tank.sprite.0] ' + | + Q.x,Q.yM[tank.goto]; + Q.s"N !* not background sprite *! + Q.c- "= + !* space is "transparent" - copy background unmodified *! + 0A"< I | 0A-10"= I | C ' ' + -A:[tank.sprite.0] + %.x F< + ' + !* "destroy" fields we have touched *! + U.d + 0A"F 0A-10"N 0A- "N 33,126M[tank.rand]U.d ' ' ' + Q.d:[tank.sprite.0] + ' + 0A"F 0A-10"N D ' ' Q.cI + %.x + ' + > +} + +@[tank.explode]{ + !!.[explosion]*oO%. + .[explosion]✹✸✶✧· + :Q.[explosion]< + 0A"F 0A-10"N D ' ' + %.i-1Q.[explosion]IR + > +} + +0U[tank.score] + +@[tank.shoot]{ + U.#dr U.yU.x + + !* FIXME: Could also be encoded into a map *! + Q.#dr-1Oright,left,up,down + !right! + 6-1%.x %.y + 1U.#dx 0U.#dy + Oend + !left! + %.y + -U.#dx 0U.#dy + Oend + !up! + 2-1%.x + 0U.#dx -U.#dy + Oend + !down! + 2-1%.x 3%.y + 0U.#dx 1U.#dy + !* fall through *! + !end! + < + (Q.#dx%.x),(Q.#dy%.y)M[tank.goto]"F ' + 0A"< ' Q.#dy"= 0A-10"= ' ' + 0A- "N 0A-10"N 1; ' ' + 0A"F 0A-10"N D ' ' I● + -DI + > + M[tank.explode] + + %[tank.score] 1SCORE: \[tank.score] +} + +@[tank.selfdestruct]{ + U.yU.x Q.x+2U.#cx Q.y+2U.#cy + .[explosion]✹✹✸✸✶✶✧✧· + 10< + Q.#cx-10U.x 20< + Q.x-1"< %.x F> ' + Q.#cy-10U.y 20< + !* d = sqrt((x - cx)^2 + ((y - cy) * aspect)^2) *! + (Q.x-Q.#cx)^*2 + ((Q.y-Q.#cy)*2)^*2 U.#d2 + + Q.r^*2 - Q.#d2"< + Q.#d2 - (Q.r+2)^*2"< + !* on shock wave *! + Q.x,Q.yM[tank.goto]"F %.y F> ' + -D Q.rQ.[explosion]I + ' + | + !* within shock wave *! + Q.x,Q.yM[tank.goto]"F %.y F> ' + -D I + ' + %.y> + %.x> + 1 + %.r> + Q.#cx,Q.#cyM[tank.goto] +} + +ESGETCOLUMNU.x :-1U.y +Q.xU.#xo Q.yU.#yo + +!* + * Normalize identations to spaces -- assumed by M[goto] + * FIXME: Will not work well with character representations. + *! +ESGETTABDRAWMODE-2"N + J <S^I; + ESGETCOLUMN-(-1ESGETCOLUMN)U.w + -D Q.w<I > + > +' + +1CONTROL: W A S D. SHOOT: SPACE. QUIT: ESCAPE. PRESS ANY KEY TO START. + +ESGETCARETSTYLEU.[caretstyle] +0ESSETCARETSTYLE + +1U.[sprite] +< + Q.#xo,Q.#yo,0M[tank.blit] !* redraw background *! + Q.xU.#xo Q.yU.#yo + + Q.x,Q.y,Q.[sprite]M[tank.blit] + 0 U.c + :Okey.U.c + F> + !key.w! + Q.y"> -%.y ' 3U.[sprite] + F> + !key.a! + Q.x,Q.y,0M[tank.blit] !* redraw background *! + Q.x"> -%.x ' 2U.[sprite] + F> + !key.s! + Q.x,Q.y,0M[tank.blit] !* redraw background *! + %.y 4U.[sprite] + F> + !key.d! + Q.x,Q.y,0M[tank.blit] !* redraw background *! + %.x 1U.[sprite] + F> + !key. ! + !* FIXME: this also scrolls due to *! + Q.x,Q.y,Q.[sprite]M[tank.shoot] + F> + !key.! + Q.x,Q.yM[tank.selfdestruct] + 1; +> + +Q.[caretstyle]ESSETCARETSTYLE diff --git a/src/core-commands.c b/src/core-commands.c index cd9a8fa..d2c8b9d 100644 --- a/src/core-commands.c +++ b/src/core-commands.c @@ -1739,8 +1739,10 @@ TECO_DEFINE_STATE(teco_state_ascii, /*$ ^[^[ ^[$ $$ ^C terminate return * [a1,a2,...]$$ -- Terminate command line or return from macro + * -$$ * [a1,a2,...]^[$ * [a1,a2,...]^C + * -^C * * Returns from the current macro invocation. * This will pass control to the calling macro immediately @@ -1754,6 +1756,8 @@ TECO_DEFINE_STATE(teco_state_ascii, * All braces opened in the current macro invocation will * be closed and their values discarded. * Only the direct arguments to \fB$$\fP will be kept. + * If the prefix sign is set (\(lq-\fB$$\fP\(rq) the command + * will always leave -1 on the stack. * * Returning from the top-level macro in batch mode * will exit the program or start up interactive mode depending @@ -1806,6 +1810,9 @@ teco_return(teco_machine_main_t *ctx, GError **error) ctx->parent.current = &teco_state_start; if (!teco_expressions_eval(FALSE, error)) return NULL; + if (teco_num_sign < 0) + /* only if you wrote -$$ */ + teco_expressions_push(1); teco_error_return_set(error, teco_expressions_args()); return NULL; } @@ -1873,6 +1880,18 @@ TECO_DEFINE_STATE_START(teco_state_escape, .end_of_macro_cb = teco_state_escape_end_of_macro ); +static gboolean +teco_state_ctlc_initial(teco_machine_main_t *ctx, GError **error) +{ + if (G_UNLIKELY(ctx == &teco_cmdline.machine)) { + g_set_error_literal(error, TECO_ERROR, TECO_ERROR_FAILED, + "<^C> is not allowed to terminate command-lines"); + return FALSE; + } + + return TRUE; +} + /* * Just like ^[, ^C actually implements a lookahead, * so a ^C itself does nothing. @@ -1892,20 +1911,20 @@ teco_state_ctlc_input(teco_machine_main_t *ctx, gunichar chr, GError **error) } static gboolean -teco_state_ctlc_initial(teco_machine_main_t *ctx, GError **error) +teco_state_ctlc_end_of_macro(teco_machine_main_t *ctx, GError **error) { - if (G_UNLIKELY(ctx == &teco_cmdline.machine)) { - g_set_error_literal(error, TECO_ERROR, TECO_ERROR_FAILED, - "<^C> is not allowed to terminate command-lines"); - return FALSE; - } - + if (ctx->flags.mode > TECO_MODE_NORMAL) + return TRUE; + if (teco_num_sign < 0) + /* only if you wrote -^C */ + teco_expressions_push(1); return TRUE; } TECO_DEFINE_STATE_START(teco_state_ctlc, .initial_cb = (teco_state_initial_cb_t)teco_state_ctlc_initial, - .input_cb = (teco_state_input_cb_t)teco_state_ctlc_input + .input_cb = (teco_state_input_cb_t)teco_state_ctlc_input, + .end_of_macro_cb = (teco_state_end_of_macro_cb_t)teco_state_ctlc_end_of_macro ); static teco_state_t * @@ -2117,46 +2136,35 @@ teco_state_ecommand_flags(teco_machine_main_t *ctx, GError **error) * first. * Memory limiting is enabled by default. * .IP 3: - * This \fBwrite-only\fP property allows redefining the - * first 16 entries of the terminal color palette \(em a - * feature required by some - * color schemes when using the Curses user interface. - * When setting this property, you are making a request - * to define the terminal \fIcolor\fP as the Scintilla-compatible - * RGB color value given in the \fIrgb\fP parameter. - * \fIcolor\fP must be a value between 0 and 15 - * corresponding to black, red, green, yellow, blue, magenta, - * cyan, white, bright black, bright red, etc. in that order. - * The \fIrgb\fP value has the format 0xBBGGRR, i.e. the red - * component is the least-significant byte and all other bytes - * are ignored. - * Note that on curses, RGB color values sent to Scintilla - * are actually mapped to these 16 colors by the Scinterm port - * and may represent colors with no resemblance to the \(lqRGB\(rq - * value used (depending on the current palette) \(em they should - * instead be viewed as placeholders for 16 standard terminal - * color codes. - * Please refer to the Scinterm manual for details on the allowed - * \(lqRGB\(rq values and how they map to terminal colors. - * This command provides a crude way to request exact RGB colors - * for the first 16 terminal colors. - * The color definition may be queued or be completely ignored - * on other user interfaces and no feedback is given - * if it fails. In fact feedback cannot be given reliably anyway. - * Note that on 8 color terminals, only the first 8 colors - * can be redefined (if you are lucky). - * Note that due to restrictions of most terminal emulators - * and some curses implementations, this command simply will not - * restore the original palette entry or request - * when rubbed out and should generally only be used in - * \fIbatch-mode\fP \(em typically when loading a color scheme. - * For the same reasons \(em even though \*(ST tries hard to - * restore the original palette on exit \(em palette changes may - * persist after \*(ST terminates on most terminal emulators on Unix. - * The only emulator which will restore their default palette - * on exit the author is aware of is \fBxterm\fP(1) and - * the Linux console driver. - * You have been warned. Good luck. + * This \fBwrite-only\fP property allows disabling use of + * the 16 color palette of default colors when using + * the Curses user interface. + * By default, when working with RGB values in Scintilla + * messages (and \*(ST color schemes for that matter) + * the 16 \(lqdefault\(rq colors are represented by + * special RGB placeholders (e.g. 0x000080 for \fICOLOR_RED\fP) + * as documented in the Scinterm manual. + * Any other RGB values will be automatically allocated + * in the terminal emulator if supported, giving the illusion + * of true color support, even though the actual number of + * concurrent colors on screen may be limited by the terminal + * emulator (see \fImax_colors\fP and \fImax_pairs\fP + * .B terminfo (1) + * capabilities) and other factors. + * \*(ST tries to avoid the first 16 color ids so as not to + * interfer with other terminal-based applications. + * The default palette however may be overwritten when requesting + * new colors in terminals restricted to 16 colors. + * In this case the original palette might not be restored properly on + * program termination and affect other terminal applications. + * The 16 predefined colors do not map to exact RGB values, + * though, but point into a palette at the terminal emulator. + * \*(ST therefore allows you to disable the 16 RGB placeholders + * by calling \(lq0,3EJ\(rq so that all colors are freshly initialized + * and will represent their exact RGB values. + * It has no effect when using the GTK interface. + * You are recommended to add \(lq0,3EJ\(rq to all color + * schemes that rely on exact RGB values. * .IP 4: * The column after the last horizontal movement. * This is only used by \fBfnkeys.tes\fP and is similar to the Scintilla-internal @@ -2169,12 +2177,14 @@ teco_state_ecommand_flags(teco_machine_main_t *ctx, GError **error) * .IP 6: * .SCITECO_TOPIC recovery * Interval in seconds for the creation of recovery files - * or 0 if those dumps are disabled (the default is 300 seconds). + * or 0 if those dumps are disabled (the default is 120 seconds). * When enabled all dirty buffers are dumped to files with hash * signs around the original basename (\fB#\fIfilename\fB#\fR). * They are removed automatically when no longer required, * but may be left around when the \*(ST crashes or terminates * unexpectedly. + * During graceful shutdowns (\fBSIGTERM\fP etc.) recovery + * files may be dumped immediately even before the interval expires. * After changing the interval, the new value may become * active only after the previous interval expires. * Recovery files are not dumped in batch mode. @@ -2229,7 +2239,7 @@ teco_state_ecommand_properties(teco_machine_main_t *ctx, GError **error) EJ_USER_INTERFACE = 0, EJ_BUFFERS, EJ_MEMORY_LIMIT, - EJ_INIT_COLOR, + EJ_PALETTE, EJ_CARETX, EJ_CMDLINE_HEIGHT, EJ_RECOVERY_INTERVAL @@ -2253,19 +2263,13 @@ teco_state_ecommand_properties(teco_machine_main_t *ctx, GError **error) return; break; - case EJ_INIT_COLOR: - if (value < 0 || value >= 16) { - g_set_error(error, TECO_ERROR, TECO_ERROR_FAILED, - "Invalid color code %" TECO_INT_FORMAT " " - "specified for <EJ>", value); - return; - } - if (!teco_expressions_args()) { - teco_error_argexpected_set(error, "EJ"); + case EJ_PALETTE: + if (teco_is_success(value)) { + g_set_error_literal(error, TECO_ERROR, TECO_ERROR_FAILED, + "Default color palette can only be disabled"); return; } - teco_interface_init_color((guint)value, - (guint32)teco_expressions_pop_num(0)); + teco_interface_disable_palette(); break; case EJ_CARETX: diff --git a/src/interface-curses/interface.c b/src/interface-curses/interface.c index 45821f9..21e728f 100644 --- a/src/interface-curses/interface.c +++ b/src/interface-curses/interface.c @@ -125,7 +125,8 @@ teco_console_ctrl_handler(DWORD type) { switch (type) { case CTRL_C_EVENT: - teco_interrupted = TRUE; + case CTRL_BREAK_EVENT: + teco_interrupted = TECO_INTERRUPTED; return TRUE; } @@ -137,6 +138,17 @@ teco_console_ctrl_handler(DWORD type) static gint teco_xterm_version(void) G_GNUC_UNUSED; static gint teco_interface_blocking_getch(void); +static inline gboolean teco_interface_check_key(gint key); + +#define MAX_COLORS (MIN(COLORS, G_MAXSHORT)/2) +/** + * Maximum effective number of color pairs. + * 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. + * Half of the range is reserved to Scinterm. + */ +#define MAX_PAIRS (MIN(COLOR_PAIRS, G_MAXSHORT)/2) /** * Get bright variant of one of the 8 standard @@ -154,6 +166,12 @@ static gint teco_interface_blocking_getch(void); * The 8 bright colors (if terminal supports at * least 16 colors), else they are identical to * the non-bright colors (default curses colors). + * + * As a consequence a light black (grey) foreground + * on black background might be invisible on 8 color + * terminals. + * If you add in A_BOLD, there is a good chance that + * the text will still become grey. */ #define COLOR_LBLACK COLOR_LIGHT(COLOR_BLACK) #define COLOR_LRED COLOR_LIGHT(COLOR_RED) @@ -166,30 +184,22 @@ static gint teco_interface_blocking_getch(void); static struct { /** + * Mapping of RGB codes (encoded into a pointer) + * to a curses color number. + */ + GHashTable *color_table; + /** * Mapping of foreground and background curses color tuples * (encoded into a pointer) to a color pair number. */ GHashTable *pair_table; - - /** - * Mapping of the first 16 curses color codes (that may or may not - * correspond with the standard terminal color codes) to - * Scintilla-compatible RGB values (red is LSB) to initialize after - * Curses startup. - * Negative values mean no color redefinition (keep the original - * palette entry). - */ - gint32 color_table[16]; - /** - * Mapping of the first 16 curses color codes to their - * original values for restoring them on shutdown. - * Unfortunately, this may not be supported on all - * curses ports, so this array may be unused. + * Whether to map the 16 standard palettized colors + * in color_table. + * Should be disabled when using arbitrary RGB values, + * so every color is initialized to exact RGB values. */ - struct { - gshort r, g, b; - } orig_color_table[16]; + gboolean use_palette; int stdin_orig, stdout_orig, stderr_orig; SCREEN *screen; @@ -264,7 +274,7 @@ teco_color_pair(attr_t *attr, gshort fg, gshort 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)) + if (G_UNLIKELY(next_pair >= MAX_PAIRS)) return 0; init_pair(next_pair, fg, bg); g_hash_table_insert(teco_interface.pair_table, key, GUINT_TO_POINTER(next_pair)); @@ -292,38 +302,60 @@ teco_rgb2curses_triple(guint32 rgb, gshort *r, gshort *g, gshort *b) *b = ((rgb & 0xFF0000) >> 16)*1000/0xFF; } +static inline void +teco_interface_insert_color(guint32 rgb, gshort color) +{ + /* + * Color ids are stored one-offset, so that COLOR_BLACK + * can be discerned from a missing entry. + */ + g_hash_table_insert(teco_interface.color_table, + GUINT_TO_POINTER(rgb), GUINT_TO_POINTER(color)+1); +} + /** * Convert a Scintilla-compatible RGB color value * (0xBBGGRR) to a Curses color code (e.g. COLOR_BLACK). - * This does not work with arbitrary RGB values but - * only the 16 RGB color values defined by Scinterm - * corresponding to the 16 terminal colors. - * It is equivalent to Scinterm's internal `term_color` - * function. + * + * This will automatically initialize new curses colors + * when necessary. + * Unless the palette is disabled with + * teco_interface_disable_palette(), this will return + * the 16 "standard" colors for a predefined list of + * RGB values (just like defined by Scinterm). */ static gshort teco_rgb2curses(guint32 rgb) { - switch (rgb) { - case 0x000000: return COLOR_BLACK; - case 0x000080: return COLOR_RED; - case 0x008000: return COLOR_GREEN; - case 0x008080: return COLOR_YELLOW; - case 0x800000: return COLOR_BLUE; - case 0x800080: return COLOR_MAGENTA; - case 0x808000: return COLOR_CYAN; - case 0xC0C0C0: return COLOR_WHITE; - case 0x404040: return COLOR_LBLACK; - case 0x0000FF: return COLOR_LRED; - case 0x00FF00: return COLOR_LGREEN; - case 0x00FFFF: return COLOR_LYELLOW; - case 0xFF0000: return COLOR_LBLUE; - case 0xFF00FF: return COLOR_LMAGENTA; - case 0xFFFF00: return COLOR_LCYAN; - case 0xFFFFFF: return COLOR_LWHITE; - } + static guint colors = 0; + + if (!has_colors()) + return COLOR_WHITE; + + gpointer value = g_hash_table_lookup(teco_interface.color_table, + GUINT_TO_POINTER(rgb)); + if (G_LIKELY(value != NULL)) + return GPOINTER_TO_UINT(value)-1; + + /* + * Even when initializing new colors, we will __try__ not to + * touch the 16 palettized colors. + * First of all, we might still need them and secondly, + * this ensures we don't have to reset them on exit + * (which is not always possible anyway). + * There can still be 16 color terminals with + * can_change_color() == TRUE, though. + */ + guint next_color = colors + (COLORS > 16 ? 16 : 0); - return COLOR_WHITE; + if (G_UNLIKELY(next_color >= MAX_COLORS) || !can_change_color()) + return COLOR_WHITE; + gshort r, g, b; + teco_rgb2curses_triple(rgb, &r, &g, &b); + init_color(next_color, r, g, b); + teco_interface_insert_color(rgb, next_color); + colors++; + return next_color; } static gint @@ -414,9 +446,6 @@ teco_view_free(teco_view_t *ctx) scintilla_delete(ctx); } -static void teco_interface_init_color_safe(guint color, guint32 rgb); -static void teco_interface_restore_colors(void); - static void teco_interface_init_screen(void); static gboolean teco_interface_init_interactive(GError **error); static void teco_interface_restore_batch(void); @@ -431,10 +460,7 @@ static void teco_interface_draw_info(void); 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; - for (guint i = 0; i < G_N_ELEMENTS(teco_interface.orig_color_table); i++) - teco_interface.orig_color_table[i].r = -1; + teco_interface.use_palette = TRUE; teco_interface.stdin_orig = teco_interface.stdout_orig = teco_interface.stderr_orig = -1; @@ -476,133 +502,11 @@ teco_interface_get_options(void) return NULL; } -static void -teco_interface_init_color_safe(guint color, guint32 rgb) -{ -#if defined(__PDCURSES__) && !defined(PDCURSES_GUI) - if (teco_interface.orig_color_table[color].r < 0) { - color_content((short)color, - &teco_interface.orig_color_table[color].r, - &teco_interface.orig_color_table[color].g, - &teco_interface.orig_color_table[color].b); - } -#endif - - gshort r, g, b; - teco_rgb2curses_triple(rgb, &r, &g, &b); - init_color((short)color, r, g, b); -} - -#if defined(__PDCURSES__) && !defined(PDCURSES_GUI) - -/* - * On PDCurses/WinCon, color_content() will actually return - * the real console color palette - or at least the default - * palette when the console started. - */ -static void -teco_interface_restore_colors(void) -{ - if (!can_change_color()) - return; - - for (guint i = 0; i < G_N_ELEMENTS(teco_interface.orig_color_table); i++) { - if (teco_interface.orig_color_table[i].r < 0) - continue; - - init_color((short)i, - teco_interface.orig_color_table[i].r, - teco_interface.orig_color_table[i].g, - teco_interface.orig_color_table[i].b); - } -} - -#elif defined(CURSES_TTY) - -/* - * FIXME: On UNIX/ncurses teco_interface_init_color_safe() __may__ - * change the terminal's palette permanently and there does not - * appear to be any portable way of restoring the original one. - * Curses has color_content(), but there is actually no terminal - * that allows querying the current palette and so color_content() - * will return bogus "default" values and only for the first 8 colors. - * It would do more damage to restore the palette returned by - * color_content() than it helps. - * xterm has the escape sequence "\e]104\a" which restores - * the palette from Xdefaults but not all terminal emulators - * claiming to be "xterm" via $TERM support this escape sequence. - * lxterminal for instance will print gibberish instead. - * So we try to look whether $XTERM_VERSION is set. - * There are hardly any other terminal emulators that support palette - * resets. - * The only emulator I'm aware of which can be identified reliably - * by $TERM supporting a palette reset is the Linux console - * (see console_codes(4)). The escape sequence "\e]R" is already - * part of its terminfo description (orig_colors capability) - * which is apparently sent by endwin(), so the palette is - * already properly restored on endwin(). - * Welcome in Curses hell. - */ -static void -teco_interface_restore_colors(void) -{ - if (teco_xterm_version() < 0) - return; - - /* - * Looks like a real XTerm - */ - fputs("\e]104\a", teco_interface.screen_tty); - fflush(teco_interface.screen_tty); -} - -#else /* (!__PDCURSES__ || PDCURSES_GUI) && !CURSES_TTY */ - -static void -teco_interface_restore_colors(void) -{ - /* - * No way to restore the palette, or it's - * unnecessary (e.g. XCurses) - */ -} - -#endif - void -teco_interface_init_color(guint color, guint32 rgb) +teco_interface_disable_palette(void) { - if (color >= G_N_ELEMENTS(teco_interface.color_table)) - return; - -#if defined(__PDCURSES__) && !defined(PDC_RGB) - /* - * PDCurses will usually number color codes differently - * (least significant bit is the blue component) while - * SciTECO macros will assume a standard terminal color - * code numbering with red as the LSB. - * Therefore we have to swap the bit order of the least - * significant 3 bits here. - */ - color = (color & ~0x5) | - ((color & 0x1) << 2) | ((color & 0x4) >> 2); -#endif - - if (teco_interface.input_pad) { - /* interactive mode */ - if (!can_change_color()) - return; - - teco_interface_init_color_safe(color, rgb); - } else { - /* - * batch mode: store colors, - * they can only be initialized after start_color() - * which is called by Scinterm when interactive - * mode is initialized - */ - teco_interface.color_table[color] = (gint32)rgb; - } + teco_interface.use_palette = FALSE; + scintilla_disable_color_palette(); } #ifdef CURSES_TTY @@ -744,14 +648,33 @@ teco_interface_init_interactive(GError **error) teco_interface_init_screen(); + teco_interface.color_table = g_hash_table_new(g_direct_hash, g_direct_equal); 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); + scintilla_set_color_offsets(MAX_COLORS, MAX_PAIRS); + + if (teco_interface.use_palette && has_colors()) { + teco_interface_insert_color(0x000000, COLOR_BLACK); + teco_interface_insert_color(0x000080, COLOR_RED); + teco_interface_insert_color(0x008000, COLOR_GREEN); + teco_interface_insert_color(0x008080, COLOR_YELLOW); + teco_interface_insert_color(0x800000, COLOR_BLUE); + teco_interface_insert_color(0x800080, COLOR_MAGENTA); + teco_interface_insert_color(0x808000, COLOR_CYAN); + teco_interface_insert_color(0xC0C0C0, COLOR_WHITE); + /* + * On 8-color terminals, we still support the + * higher (light) colors, but map them to the lower codes as well. + */ + teco_interface_insert_color(0x404040, COLOR_LBLACK); + teco_interface_insert_color(0x0000FF, COLOR_LRED); + teco_interface_insert_color(0x00FF00, COLOR_LGREEN); + teco_interface_insert_color(0x00FFFF, COLOR_LYELLOW); + teco_interface_insert_color(0xFF0000, COLOR_LBLUE); + teco_interface_insert_color(0xFF00FF, COLOR_LMAGENTA); + teco_interface_insert_color(0xFFFF00, COLOR_LCYAN); + teco_interface_insert_color(0xFFFFFF, COLOR_LWHITE); + } /* * On UNIX terminals, the escape key is usually @@ -833,19 +756,6 @@ teco_interface_init_interactive(GError **error) teco_interface_show_view(teco_interface_current_view); /* - * Only now it's safe to redefine the 16 default colors. - */ - if (can_change_color()) { - for (guint i = 0; i < G_N_ELEMENTS(teco_interface.color_table); i++) { - /* - * init_color() may still fail if COLORS < 16 - */ - if (teco_interface.color_table[i] >= 0) - teco_interface_init_color_safe(i, (guint32)teco_interface.color_table[i]); - } - } - - /* * Only now (in interactive mode), it's safe to initialize * the clipboard Q-Registers on ncurses with a compatible terminal * emulator since clipboard operations will no longer interfer @@ -877,7 +787,6 @@ teco_interface_restore_batch(void) * (i.e. return to batch mode) */ endwin(); - teco_interface_restore_colors(); /* * Restore stdin, stdout and stderr, so output goes to @@ -1004,15 +913,30 @@ teco_interface_getch(gboolean widechar) gint32 cp; do { - cp = teco_interface_blocking_getch(); - if (cp == TECO_CTL_KEY('C')) - teco_interrupted = TRUE; - if (cp == TECO_CTL_KEY('C') || cp == TECO_CTL_KEY('D')) { - cp = -1; - break; - } - if (cp < 0 || cp > 0xFF) - continue; + do { + cp = teco_interface_blocking_getch(); + switch (cp) { +#ifdef KEY_RESIZE + case KEY_RESIZE: + teco_interface_resize_all_windows(); + teco_interface_refresh(FALSE); + /* cursor was moved by the resize */ + wmove(teco_interface.msg_window, 0, 0); + wrefresh(teco_interface.msg_window); + break; +#endif + case KEY_BACKSPACE: + return TECO_CTL_KEY('H'); + case KEY_ENTER: + return '\n'; + case TECO_CTL_KEY('C'): + teco_interrupted = TECO_INTERRUPTED; + /* fall through */ + case TECO_CTL_KEY('D'): + /* emulates EOF on stdin */ + return -1; + } + } while (cp < 0 || cp > 0xFF || !teco_interface_check_key(cp)); if (!widechar || !cp) break; @@ -1783,7 +1707,7 @@ teco_interface_popup_clear(void) gboolean teco_interface_is_interrupted(void) { - return teco_interrupted != FALSE; + return teco_interrupted == TECO_INTERRUPTED; } #else /* !CURSES_TTY && !PDCURSES_WINCON && !NCURSES_WIN32 */ @@ -1802,7 +1726,7 @@ teco_interface_is_interrupted(void) { if (!teco_interface.input_pad) /* batch mode */ - return teco_interrupted != FALSE; + return teco_interrupted == TECO_INTERRUPTED; /* * NOTE: wgetch() is configured to be nonblocking. @@ -1817,7 +1741,7 @@ teco_interface_is_interrupted(void) GINT_TO_POINTER(key)); } - return teco_interrupted != FALSE; + return teco_interrupted == TECO_INTERRUPTED; } #endif @@ -2106,7 +2030,7 @@ teco_interface_blocking_getch(void) gint key = wgetch(teco_interface.input_pad); teco_memory_start_limiting(); /* allow asynchronous interruptions on <CTRL/C> */ - teco_interrupted = FALSE; + teco_interrupted = TECO_NORMAL; wtimeout(teco_interface.input_pad, 0); #if defined(CURSES_TTY) || defined(PDCURSES_WINCON) || defined(NCURSES_WIN32) noraw(); /* FIXME: necessary because of NCURSES_WIN32 bug */ @@ -2122,6 +2046,31 @@ teco_interface_blocking_getch(void) return key; } +#ifdef __PDCURSES__ + +/* + * Especially PDCurses/WinGUI likes to report two keypresses, + * e.g. for CTRL+Shift+6 (CTRL+^). + * Make sure we don't filter out AltGr, which may be reported as CTRL+ALT. + */ +static inline gboolean +teco_interface_check_key(gint key) +{ + return (PDC_get_key_modifiers() & + (PDC_KEY_MODIFIER_CONTROL | PDC_KEY_MODIFIER_ALT)) != PDC_KEY_MODIFIER_CONTROL || + TECO_IS_CTL(key); +} + +#else /* __PDCURSES__ */ + +static inline gboolean +teco_interface_check_key(gint key) +{ + return TRUE; +} + +#endif + /** * One iteration of the event loop. * @@ -2227,22 +2176,10 @@ teco_interface_event_loop_iter(void) * Control keys and keys with printable representation */ default: - if (key > 0xFF) - /* unhandled function key */ + if (key > 0xFF || !teco_interface_check_key(key)) + /* unhandled function key or bogus key press */ return; -#ifdef __PDCURSES__ - /* - * Especially PDCurses/WinGUI likes to report two keypresses, - * e.g. for CTRL+Shift+6 (CTRL+^). - * Make sure we don't filter out AltGr, which may be reported as CTRL+ALT. - */ - if ((PDC_get_key_modifiers() & - (PDC_KEY_MODIFIER_CONTROL | PDC_KEY_MODIFIER_ALT)) == PDC_KEY_MODIFIER_CONTROL && - !TECO_IS_CTL(key)) - return; -#endif - /* * NOTE: There's also wget_wch(), but it requires * a widechar version of Curses. @@ -2373,6 +2310,8 @@ teco_interface_cleanup(void) if (teco_interface.stdout_orig >= 0) close(teco_interface.stdout_orig); + if (teco_interface.color_table) + g_hash_table_destroy(teco_interface.color_table); if (teco_interface.pair_table) g_hash_table_destroy(teco_interface.pair_table); diff --git a/src/interface-gtk/interface.c b/src/interface-gtk/interface.c index 08ccf5d..9ef86a1 100644 --- a/src/interface-gtk/interface.c +++ b/src/interface-gtk/interface.c @@ -78,7 +78,7 @@ static void teco_interface_popup_clicked_cb(GtkWidget *popup, gchar *str, gulong gpointer user_data); static gboolean teco_interface_window_delete_cb(GtkWidget *widget, GdkEventAny *event, gpointer user_data); -static gboolean teco_interface_sigterm_handler(gpointer user_data) G_GNUC_UNUSED; +static gboolean teco_interface_termination_handler(gpointer user_data) G_GNUC_UNUSED; static gchar teco_interface_get_ansi_key(GdkEventKey *event); #define TECO_UNNAMED_FILE "(Unnamed)" @@ -404,7 +404,7 @@ teco_interface_get_options(void) return group; } -void teco_interface_init_color(guint color, guint32 rgb) {} +void teco_interface_disable_palette(void) {} void teco_interface_msg_literal(teco_msg_t type, const gchar *str, gsize len) @@ -451,14 +451,15 @@ teco_interface_getch_commit_cb(GtkIMContext *context, gchar *str, gpointer user_ */ *cp = g_utf8_get_char_validated(str, -1); g_assert(*cp >= 0); - gtk_main_quit(); + + /* we might be invoked outside of a nested event loop */ + if (gtk_main_level() > 1) + gtk_main_quit(); } static gboolean -teco_interface_getch_input_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data) +teco_interface_getch_process_event(GdkEvent *event, teco_int_t *cp) { - teco_int_t *cp = user_data; - g_assert(event->type == GDK_KEY_PRESS); switch (event->key.keyval) { @@ -476,19 +477,34 @@ teco_interface_getch_input_cb(GtkWidget *widget, GdkEvent *event, gpointer user_ *cp = TECO_CTL_KEY(g_ascii_toupper(*cp)); switch (*cp) { case TECO_CTL_KEY('C'): - teco_interrupted = TRUE; + teco_interrupted = TECO_INTERRUPTED; /* fall through */ case TECO_CTL_KEY('D'): + /* emulates EOF on stdin */ *cp = -1; } break; } + /* + * NOTE: The teco_interface_getch_commit_cb() could be called immediately + * without returning to the event loop. + */ gtk_im_context_filter_keypress(teco_interface.input_method, &event->key); - return TRUE; + return *cp >= 0; } - gtk_main_quit(); + return TRUE; +} + +static gboolean +teco_interface_getch_input_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data) +{ + teco_int_t *cp = user_data; + + if (teco_interface_getch_process_event(event, cp)) + gtk_main_quit(); + return TRUE; } @@ -513,6 +529,22 @@ teco_interface_getch(gboolean widechar) G_CALLBACK(teco_interface_getch_commit_cb), &cp); /* + * The original teco_interface_input_cb() could have already enqueued events + * (also between ^T calls). + * This must be done after registering teco_interface_getch_commit_cb() already. + * + * NOTE: Already enqueued mouse events will currently be discarded silently. + */ + for (;;) { + g_autoptr(GdkEvent) event = g_queue_pop_head(teco_interface.event_queue); + if (!event) + break; + if (event->type == GDK_KEY_PRESS && + teco_interface_getch_process_event(event, &cp)) + goto cleanup; + } + + /* * Highlights the first character in the label. * This mimics what the Curses UI does. * Is there a better way to signal that we expect input? @@ -526,6 +558,7 @@ teco_interface_getch(gboolean widechar) gdk_window_freeze_updates(top_window); +cleanup: g_signal_handler_disconnect(teco_interface.input_method, commit_handler); g_signal_handlers_unblock_by_func(teco_interface.input_method, teco_interface_cmdline_commit_cb, NULL); g_signal_handler_disconnect(teco_interface.window, key_handler); @@ -790,7 +823,7 @@ teco_interface_is_interrupted(void) { if (!gtk_main_level()) /* batch mode */ - return teco_interrupted != FALSE; + return teco_interrupted == TECO_INTERRUPTED; /* * By polling only every TECO_POLL_INTERVAL microseconds @@ -800,11 +833,11 @@ teco_interface_is_interrupted(void) guint64 now_ts = g_get_monotonic_time(); if (G_LIKELY(last_poll_ts+TECO_POLL_INTERVAL > now_ts)) - return teco_interrupted != FALSE; + return teco_interrupted == TECO_INTERRUPTED; last_poll_ts = now_ts; gtk_main_iteration_do(FALSE); - return teco_interrupted != FALSE; + return teco_interrupted == TECO_INTERRUPTED; } void @@ -1265,13 +1298,12 @@ teco_interface_event_loop(GError **error) #endif /* - * SIGTERM emulates the "Close" key just like when - * closing the window if supported by this version of glib. - * Note that this replaces SciTECO's default SIGTERM handler - * so it will additionally raise(SIGINT). + * SIGTERM and SIGHUP terminate the program, but will + * dump recovery files first (if enabled). */ #ifdef G_OS_UNIX - g_unix_signal_add(SIGTERM, teco_interface_sigterm_handler, NULL); + g_unix_signal_add(SIGTERM, teco_interface_termination_handler, NULL); + g_unix_signal_add(SIGHUP, teco_interface_termination_handler, NULL); #endif /* the interval might have been changed in the profile */ @@ -1395,7 +1427,7 @@ teco_interface_input_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data) * If the execution thread is currently blocking, * the key is delivered like an ordinary key press. */ - teco_interrupted = TRUE; + teco_interrupted = TECO_INTERRUPTED; else g_queue_push_tail(teco_interface.event_queue, gdk_event_copy(event)); @@ -1436,7 +1468,7 @@ teco_interface_input_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data) const teco_view_t *last_view = teco_interface_current_view; sptr_t last_vpos = teco_interface_ssm(SCI_GETFIRSTVISIBLELINE, 0, 0); - teco_interrupted = FALSE; + teco_interrupted = TECO_NORMAL; switch (event->type) { case GDK_KEY_PRESS: teco_interface_handle_key_press(&event->key, &error); @@ -1453,7 +1485,7 @@ teco_interface_input_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data) default: g_assert_not_reached(); } - teco_interrupted = FALSE; + teco_interrupted = TECO_NORMAL; teco_interface_update(teco_interface_current_view != last_view); /* always expand folds, even after mouse clicks */ @@ -1563,16 +1595,23 @@ teco_interface_window_delete_cb(GtkWidget *widget, GdkEventAny *event, gpointer } static gboolean -teco_interface_sigterm_handler(gpointer user_data) +teco_interface_termination_handler(gpointer user_data) { + teco_interface_msg(TECO_MSG_WARNING, "Received termination signal - dumping recovery files"); + teco_interrupted = TECO_TERMINATED; + /* - * Similar to window deletion - emulate "close" key press. + * This may be an emergency shutdown or another kind of + * termination that we cannot ignore, so better dump + * recovery files before terminating. */ - GtkWidget *widget = teco_interface.window; + if (teco_ring_recovery_interval != 0) + teco_ring_dump_recovery(); - g_autoptr(GdkEvent) close_event = gdk_event_new(GDK_KEY_PRESS); - close_event->key.window = gtk_widget_get_parent_window(widget); - close_event->key.keyval = GDK_KEY_Close; + /* + * Otherwise we terminate and clean up as if by `-EX`. + */ + gtk_main_quit(); - return teco_interface_input_cb(widget, close_event, NULL); + return G_SOURCE_REMOVE; } diff --git a/src/interface.h b/src/interface.h index 54f807b..ace0e3d 100644 --- a/src/interface.h +++ b/src/interface.h @@ -57,13 +57,14 @@ void teco_interface_init(gint argc, gchar **argv); GOptionGroup *teco_interface_get_options(void); /** @pure makes sense only on Curses */ -void teco_interface_init_color(guint color, guint32 rgb); +void teco_interface_disable_palette(void); typedef enum { - TECO_MSG_USER, + TECO_MSG_USER = 0, TECO_MSG_INFO, TECO_MSG_WARNING, - TECO_MSG_ERROR + TECO_MSG_ERROR, + TECO_MSG_MAX = TECO_MSG_ERROR } teco_msg_t; extern teco_msg_t teco_interface_msg_level; @@ -66,12 +66,15 @@ teco_int_t teco_ed = TECO_ED_AUTOEOL; /** - * Whether there was an asyncronous interruption (usually after pressing CTRL+C). + * Whether there was an asynchronous interruption (usually after + * pressing CTRL+C) or termination (SIGTERM). * However you should always use teco_interface_is_interrupted(), * to check for interruptions because of its side effects. * This variable is safe to set to TRUE from signal handlers and threads. + * + * This is a teco_interrupted_t. */ -volatile sig_atomic_t teco_interrupted = FALSE; +volatile sig_atomic_t teco_interrupted = TECO_NORMAL; /* * FIXME: Move this into file-utils.c? @@ -346,7 +349,7 @@ teco_initialize_environment(void) static void teco_sigint_handler(int signal) { - teco_interrupted = TRUE; + teco_interrupted = TECO_INTERRUPTED; } #ifdef G_OS_WIN32 @@ -385,8 +388,21 @@ main(int argc, char **argv) getchar(); #endif + /* + * FIXME: Gracefully handle SIGTERM. + * This however would require polling for the flag in Curses + * getch() loops. + * GTK already catches SIGTERM. + */ +#ifdef HAVE_SIGACTION + static const struct sigaction sigint = { + .sa_handler = teco_sigint_handler, + .sa_flags = 0 /* don't auto-restart syscalls */ + }; + sigaction(SIGINT, &sigint, NULL); +#else signal(SIGINT, teco_sigint_handler); - signal(SIGTERM, teco_sigint_handler); +#endif /* * Important for Unicode handling in curses and glib. @@ -143,7 +143,12 @@ teco_buffer_save(teco_buffer_t *ctx, const gchar *filename, GError **error) static inline void teco_buffer_free(teco_buffer_t *ctx) { - if (ctx->state > TECO_BUFFER_DIRTY_NO_DUMP) { + /* + * During graceful, but unexpected shutdowns (SIGTERM etc.), + * we must preserve the recovery files. + */ + if (ctx->state > TECO_BUFFER_DIRTY_NO_DUMP && + teco_interrupted != TECO_TERMINATED) { g_autofree gchar *filename_recovery = teco_buffer_get_recovery(ctx); g_unlink(filename_recovery); } @@ -312,12 +317,13 @@ teco_ring_save_all_dirty_buffers(GError **error) * Recovery creation interval in seconds or 0 if disabled. * It's not currently enforced in batch mode. */ -guint teco_ring_recovery_interval = 5*60; +guint teco_ring_recovery_interval = 2*60; /** * Create recovery files for all dirty buffers. * - * Should be called by the interface every teco_ring_recovery_interval seconds. + * Should be called by the interface every teco_ring_recovery_interval seconds + * or before graceful terminations (SIGTERM etc.). * This does not generate or expect undo tokens, so it can be called * even when idlying. */ diff --git a/src/sciteco.h b/src/sciteco.h index 16dba69..88078c2 100644 --- a/src/sciteco.h +++ b/src/sciteco.h @@ -109,6 +109,12 @@ teco_default_codepage(void) return teco_ed & TECO_ED_DEFAULT_ANSI ? SC_CHARSET_ANSI : SC_CP_UTF8; } +typedef enum { + TECO_NORMAL = 0, + TECO_INTERRUPTED, + TECO_TERMINATED +} teco_interrupted_t; + /* in main.c */ extern volatile sig_atomic_t teco_interrupted; diff --git a/src/spawn.c b/src/spawn.c index 61718fd..716bafa 100644 --- a/src/spawn.c +++ b/src/spawn.c @@ -869,7 +869,7 @@ teco_spawn_idle_cb(gpointer user_data) { if (G_LIKELY(!teco_interface_is_interrupted())) return G_SOURCE_CONTINUE; - teco_interrupted = FALSE; + teco_interrupted = TECO_NORMAL; /* * The first CTRL+C will try to gracefully terminate the process. diff --git a/src/stdio-commands.c b/src/stdio-commands.c index abb6566..c2a1c16 100644 --- a/src/stdio-commands.c +++ b/src/stdio-commands.c @@ -255,17 +255,42 @@ teco_state_print_string_initial(teco_machine_main_t *ctx, GError **error) static teco_state_t * teco_state_print_string_done(teco_machine_main_t *ctx, teco_string_t str, GError **error) { - teco_interface_msg_literal(TECO_MSG_USER, str.data, str.len); + teco_int_t type; + + if (ctx->flags.mode > TECO_MODE_NORMAL) + return &teco_state_start; + + if (!teco_expressions_pop_num_calc(&type, TECO_MSG_USER, error)) + return NULL; + if (type < TECO_MSG_USER || type > TECO_MSG_MAX) { + g_set_error_literal(error, TECO_ERROR, TECO_ERROR_FAILED, + "Invalid message level specified for <^A>"); + return NULL; + } + + teco_interface_msg_literal(type, str.data, str.len); return &teco_state_start; } /*$ "^A" ":^A" print "print string" - * ^A<string>^A -- Print string as message - * @^A/string/ - * :^A<string>^A + * [type]^A<string>^A -- Print string as message + * [type]@^A/string/ + * [type]:^A<string>^A * - * Print <string> as a message, i.e. in the message line - * in interactive mode and if possible on the terminal (stdout) as well. + * Print <string> as a message with severity <type>, i.e. in the + * message line in interactive mode and if possible on the terminal + * as well. + * The following message levels are supported: + * .IP 0: 3 + * User-level message: + * They are written without any prefixes directly to stdout. + * This is the default if <type> is omitted. + * .IP 1: + * Info-level message + * .IP 2: + * Warnings + * .IP 3: + * Errors * * \fB^A\fP differs from all other commands in the way <string> * is terminated. @@ -112,9 +112,9 @@ teco_view_setup(teco_view_t *ctx) teco_view_ssm(ctx, SCI_SETCARETFORE, 0xFFFFFF, 0); teco_view_ssm(ctx, SCI_SETSELFORE, TRUE, 0x000000); - teco_view_ssm(ctx, SCI_SETSELBACK, TRUE, 0xFFFFFF); + teco_view_ssm(ctx, SCI_SETSELBACK, TRUE, 0xC0C0C0); - teco_view_ssm(ctx, SCI_STYLESETFORE, STYLE_DEFAULT, 0xFFFFFF); + teco_view_ssm(ctx, SCI_STYLESETFORE, STYLE_DEFAULT, 0xC0C0C0); teco_view_ssm(ctx, SCI_STYLESETBACK, STYLE_DEFAULT, 0x000000); teco_view_ssm(ctx, SCI_STYLESETFONT, STYLE_DEFAULT, (sptr_t)"Monospace"); teco_view_ssm(ctx, SCI_STYLECLEARALL, 0, 0); @@ -234,8 +234,8 @@ teco_view_load_from_channel(teco_view_t *ctx, GIOChannel *channel, */ guint cp = teco_view_get_codepage(ctx); if (cp == SC_CP_UTF8) - teco_interface_ssm(SCI_RELEASELINECHARACTERINDEX, - SC_LINECHARACTERINDEX_UTF32, 0); + teco_view_ssm(ctx, SCI_RELEASELINECHARACTERINDEX, + SC_LINECHARACTERINDEX_UTF32, 0); teco_view_ssm(ctx, SCI_BEGINUNDOACTION, 0, 0); if (clear) { @@ -314,8 +314,8 @@ cleanup: teco_view_ssm(ctx, SCI_ENDUNDOACTION, 0, 0); if (cp == SC_CP_UTF8) - teco_interface_ssm(SCI_ALLOCATELINECHARACTERINDEX, - SC_LINECHARACTERINDEX_UTF32, 0); + teco_view_ssm(ctx, SCI_ALLOCATELINECHARACTERINDEX, + SC_LINECHARACTERINDEX_UTF32, 0); return ret; } diff --git a/tests/testsuite.at b/tests/testsuite.at index 8145e3d..74fab24 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -221,6 +221,13 @@ AT_DATA([expout], [[TEST Line 2 ]]) TE_CHECK([[@^A/TEST^JLine 2^J/]], 0, expout, ignore) +# "Info" messages would be surpressed by --quiet. +AT_CHECK([[$SCITECO -e '1@^A/TEST/']], 0, stdout, ignore) +AT_FAIL_IF([! $GREP "^Info:" stdout]) +TE_CHECK([[2@^A/TEST/]], 0, ignore, stderr) +AT_FAIL_IF([! $GREP "^Warning:" stderr]) +TE_CHECK([[3@^A/TEST/]], 0, ignore, stderr) +AT_FAIL_IF([! $GREP "^Error:" stderr]) AT_CLEANUP AT_SETUP([Type out buffer contents]) @@ -301,6 +308,10 @@ AT_DATA([test.txt], [[0123456789 TE_CHECK([[@ER"test.txt" ^S+11"N(0/0)']], 0, ignore, ignore) AT_CLEANUP +AT_SETUP([Macro calls]) +TE_CHECK([[@^Ua{-$$} Ma+1"N(0/0)']], 0, ignore, ignore) +AT_CLEANUP + AT_SETUP([Editing local registers in macro calls]) TE_CHECK([[@^Ua{@EQ.x//} :Ma @^U.x/FOO/]], 0, ignore, ignore) TE_CHECK([[@^Ua{@EQ.x//} Ma @^U.x/FOO/]], 1, ignore, ignore) @@ -667,6 +678,12 @@ TE_CHECK([[@^Um{U.a Q.a-100000"<%.aMm'} 0Mm]], 0, ignore, ignore) AT_XFAIL_IF(true) AT_CLEANUP +AT_SETUP([Backtracking in patterns]) +# ^ES should be greedy and posessive +TE_CHECK([[@I/ /J :@S/^ES^X/"S(0/0)']], 0, ignore, ignore) +AT_XFAIL_IF(true) +AT_CLEANUP + AT_SETUP([Rub out from empty string argument]) # Should rub out the modifiers as well. # Will currently fail because it tries to execute `:@{`. 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 |
