Ann: SWI-Prolog 10.1.14

Dear SWI-Prolog user,

SWI-Prolog 10.1.14 is ready for download. There are a large number of
changes. Some bug fixes and notably a lot of work improving the
development tools. Highlights:

  • Bug in atom-GC for dying threads that unregister atoms after tearing
    down the Prolog engine. This notably concerns thread-local predicates
    and local tables.
  • Fix handling very large integers on Windows. Here we have, besides the
    memory limit, a 512Mb limit inside libGMP. Also fixes several integer
    operations for values > 2^{31}, silently truncating. Note that these
    issues only appear on Windows because he C type long is 32 bits there.
    It also only affects libGMP integers. The libBF API uses int64_t and
    is thus not affected.
  • Avoid child processes inheriting socket file descriptors.
  • Fixes to halting Prolog from various locations (menus, threads, etc.)

Development tools

  • Introduced more theme support and TTY links in Prolog messages. Pretty
    much any reference to a predicate is now a link. When tracing, the goal
    is a link to the call-site. This means (typically) Ctrl-click on a goal
    in the debugger edits the call-site. This works in Epilog as well as
    any terminal that supports OSC 8 escape sequences.

  • Introduce OSC 133 semantic marks. These allow the terminal to distinguish
    prompts, user input and command output. These are handled by Epilog,
    providing folding of the output of commands as well as copying the command,
    its output or both. Using the resource prolog_terminal.fold_previous: @on,
    old commands are automatically folded, leaving only commands and the output
    of the last command visible. Please try! Various modern terminals also
    support OSC 133 (e.g., iTerm2 on MacOS).

  • Many fixes and enhancements to Epilog.

    Enjoy — Jan

SWI-Prolog Changelog since version 10.1.13

  • MAINTENANCE: Added scripts/submodule-update Updates the submodules
    like git submodule update, but pulls a submodule that is on a branch
    tracking a remote branch instead of detaching its HEAD.

  • FIXED: only write OSC 8 hyperlinks to a terminal ansi_hyperlink/3
    wrote the escape sequence whenever the hyperlink_term flag was set,
    also when the stream was a memory stream. A message captured with
    with_output_to/2 then came back with the escapes in it, which broke
    test_messages.pl for anyone running with hyperlinks enabled.

  • TEST: split tests/core into tests/core_text and tests/core_lang
    tests/core was the longest running swipl test at 13.8 seconds,
    holding back “ctest -j”. Split it in two along the obvious line:
    core_text holds the tests for characters, strings, encodings, syntax,
    read/write and stream I/O, core_lang the tests for terms, arithmetic,
    control, compilation and the runtime.

  • TEST: test_agc_margin: build the filler atom once per size atom_of/3
    rebuilt a 100,000 element code list for each of the 200 atoms in
    every trigger test, which made this file 10.7 of the 16.4 seconds of
    the core test suite. The list only depends on the requested size,
    so build one per size and share it. Runs in 0.1 second now; the
    atoms it creates are still distinct and still 100kB each.

  • ENHANCED: locale independent character classification and case
    conversion code_type/2, char_type/2, upcase_atom/2, downcase_atom/2 and
    the other text primitives no longer call <wctype.h>. Character classes
    and case conversion are derived from the Unicode Character Database
    at build time, so they answer the same in every locale and on every
    C library, cover the full Unicode range also on Windows where wint_t
    is 16 bits, and agree with the classification read/1 uses.

  • FIXED: #1517 crash in atom-GC while destroying a thread or engine
    Destroying a thread or engine that holds many atoms, notably in
    its private tables, could crash in PL_unregister_atom() if the atom
    garbage collector reclaimed one of these atoms concurrently.

  • FIXED: normalize_space/2 to normalize Unicode separator characters
    normalize_space/2 used unicode_separator(), which implements the
    UAX #31 Pattern_White_Space set used by the Prolog reader. As a
    result it did not normalize the Unicode separator characters such
    as U+00A0 (no-break space) or U+3000 (ideographic space), while it
    did replace the invisible bidi format characters U+200E and U+200F
    by a space. It now uses fiswspace(), i.e., the same classification
    as code_type(Code, space).

  • DOC: document the maximum size of unbounded integers Unbounded integers
    are limited by the global stack limit and, if the system is built
    using GMP on a platform where long is 32 bits (i.e., Windows),
    to 512Mb. Document this in \secref{morelimits} and refer to it from
    the description of **/2.

  • FIXED: Windows crash creating very large integers If long is 32 bits,
    as on Windows, GMP integers are limited to 512Mb and GMP calls abort()
    if we ask for more. Our checks only verified the result fits in the
    global stack limit (1Gb by default), so for example X is 2^4294967294
    took the entire process down. In addition, the exponent was truncated
    to unsigned long, which made X is 2^4294967296 silently evaluate
    to 1.

  • CMAKE: test_libs() and test_lib() take OPTIONS Commandline options
    for swipl itself, handed to it before the test is loaded: a -D flag
    the test needs set before its libraries are, a -p that only it wants,
    and the like. There was nowhere to put such a thing: the command is
    built inside test_lib(), so a package that needed one had to register
    its tests by hand.

  • ADDED: PL_prompt_is_continuation() Says whether the prompt that
    comes next continues an input that was started earlier, which is what
    prompt1/1 and PrologPrompt() already decide between: the prompt of a
    first line is handed out once, and everything after it is the prompt
    of prompt/2.

  • FIXED: crash when a second Epilog window is deleted Updates xpce.
    The terminals share the interned Colour objects of their palette but
    held them with a flag rather than a count, so deleting one Epilog
    window freed colours the others were still painting with.

  • ADDED: el_set/2 prompt_marks(Boolean) Updates libedit and xpce.
    Turns the OSC 133 prompt marks off for a terminal that would print
    them rather than read them. They are on by default.

  • ADDED: OSC 133 semantic prompt marks Updates libedit and xpce.
    The commandline editor marks its prompts and the line it reads with the
    FinalTerm OSC 133 sequences, and the Epilog terminal reads them: it now
    knows when there is a line being edited and where it starts, rather than
    deducing it from bracketed paste. That gives click-to-move-the-caret
    back to vi mode, and terminals with shell integration (iTerm2, kitty,
    WezTerm, VS Code) get prompt navigation over a swipl session for free.

  • FIXED: a click in the Epilog terminal disturbed a single character
    read Updates libedit and xpce. A click in the line being edited asks
    the client to move its caret with cursor keys; a client reading a
    single character answered with the ESC of the first of them, which
    made the command line tracer print “Unknown option (h for help)”
    when a link in its port message was clicked.

  • FIXED: Missing empty line after a bullet list in help/1 output A list
    nested in the body of a definition list (dd) was formatted as a nested
    list, losing the empty lines that separate it from the surrounding text.

  • DOC: ansi_format/3: use code markup for the ‘#RGB’ colour names These
    are Prolog atoms, so they belong in code markup. This also avoids
    the LaTeX translation of the quotes into typographic quotes.

  • FIXED: Spacing of infix operators in term description items
    A comma binds to the left operand and is followed by a space.
    Adds \infixopsep{Op}, used by \infixterm and \infixtermitem, which
    also keeps a module qualifier free of surrounding spaces.

  • ADDED: Epilog terminal: highlight the other occurrences of the
    selection Updated xpce. The dark theme had no isearch styles for
    terminal_image, so the pale turquoise of the other matches was drawn
    with the terminal’s white foreground; both are now given colour :=
    black, as the editor entry already does.

  • FIXED: user streams lose FD_CLOEXEC when restore_ctty() reconnects
    them dup2() does not carry the flag over, so after a child revoked
    our controlling terminal and restore_ctty() opened it again, the
    standard streams were inherited by the next process we start.

  • MODIFIED: ansi_get_color/2 now reports floats in 0.0..1.0 The
    components of the rgb/3 term were integers in the range 0..65535.
    That range is ambiguous with the rgb/3 term of win_window_color/2,
    whose components are in 0..255, and it suggested a precision the
    terminal does not offer: it reports one to four hexadecimal digits
    per component, which we scaled up to 16 bits. A component is now
    the fraction of its maximum, which needs no scale to be agreed upon.
    This is an incompatible change to a predicate that is rarely used
    outside library(theme/auto).

  • ENHANCED: Hyperlink and stripe the goals printed by the debugger Goals
    printed by the debugger are now a hyperlink to their call site, i.e.,
    the position in the clause of the parent frame from which the goal
    is called. They also carry the new colour class goal(Port, Parity),
    where Parity alternates over the steps of a trace. This allows themes
    to separate successive steps using a soft background colour and/or
    to colour the goal by port. The dark and light themes stripe the goals.

  • ENHANCED: Centralise predicate references in messages and make them
    links boot/messages.pl formatted a predicate reference in some forty
    places, using four different module-hiding policies, three copies of
    the source location lookup and a mix of ~q and ~p. Only one of them
    produced a link. All of them now go through predicate_reference//1,2,
    which prints the predicate indicator using the code class and turns
    it into a hyperlink to its definition when the location is known.
    Messages that list candidates, such as the alternatives for an unknown
    procedure, tag each predicate with its kind using predicate_kind/2
    and the new themeable class predicate(Kind).

  • ENHANCED: Central source location for predicates, including C predicates
    Added ‘$predicate_source_location’/2, which resolves a predicate
    to File:Line. It follows imported_from/1 to the module that defines
    the predicate and falls back to the location of the implementing C
    function for foreign predicates. The (expensive) foreign lookup runs
    addr2line or atos in a child process and is therefore memoised.

  • ENHANCED: Hook prolog:line_editor_attributes/2 Tell the line editor how
    to switch the decoration of the input line off and on again. It must
    switch these off before erasing the rows the line no longer uses,
    as erasing paints with the current background colour. Called each
    time we build a prompt, so a theme loaded at run time is picked up.

  • FIXED: ansi_get_color/2: accept the colour replies terminals really
    send The reply was matched against a fixed pattern of exactly four
    hex digits per component terminated by BEL, which is what xterm sends.
    An X11 colour specification allows one to four digits per component and
    the string may be terminated by BEL or ST, which made ansi_get_color/2
    fail on terminals that answer the query perfectly well. The Epilog
    terminal is one of these: it replies with two digits and ST.

  • ENHANCED: Colour the toplevel prompt, the typed query and the answers
    The interactive toplevel now decorates the prompt, the text typed by
    the user and the answers using the theme classes prompt, input,
    answer(Parity) and binding(name). Parity is odd or even and
    alternates over the answers of a single query, which allows a theme to
    stripe the answers of a non-deterministic query. The default theme
    only makes the prompt and the variable names bold; the background
    colours are defined by library(theme/dark) and library(theme/light)
    as these require knowing the background colour of the terminal.

  • SUBMODULE: xpce: background colour erase and terminal identification
    Provides two fixes needed by the coloured toplevel:

  • CMAKE: Create .dSYM bundles on macOS On macOS the DWARF stays
    in the object files and the linked binary only carries a debug
    map that points at them. atos(1) follows that map, which is how
    ‘$foreign_predicate_source’/2 finds the source of a predicate defined
    in C, used by edit/1 and for the links in messages. The map breaks
    when the objects are removed and some toolchains produce one atos
    cannot follow: a MacPorts gcc build resolves no source line at all.
    Running dsymutil(1) after the link collects the DWARF into a .dSYM
    bundle, which atos locates by UUID, and fixes both.

  • FIXED: addr2line: do not report “at” without a source location
    Without source line information atos(1) emits “func (in lib.dylib) +
    0” and addr2line(1) emits “??:0”. We turned both into "func() at ",
    which is worse than the bare “func()”. The " at " is now only added
    once we know a location follows.

  • FIXED: halt/0 from an event callback did not take effect until input
    arrived With the SDL backend XPCE has no separate pce thread, so
    events for the main thread are dispatched from PL_dispatch() while
    the toplevel waits for terminal input. A callback such as Epilog’s
    “Halt Prolog” therefore raises unwind(halt(Status)) in the waiting
    thread itself, but the wait loop only asked PL_handle_signals(), which
    returns 0 when no signal is pending. Dispatching continued until
    the user typed a character, and $raw_read/2 then returned end_of_file
    with the exception still pending, printing “did not clear exception:
    unwind(halt(0))”.

  • FIXED: Windows: Control-C only interrupted the first computation
    #1515 The console control handler runs on a thread of its own, which
    has no Prolog engine, so PL_raise() had nothing to raise SIGINT on.
    It should call PL_w32thread_raise(), but the #ifdef O_PLMT guarding
    that never held: pl-main.c does not see config.h. What made ^C work
    at all was the C runtime’s own handler, installed when PL_initialise()
    calls signal(SIGINT, …) and therefore called first. As it resets
    the handler to SIG_DFL before calling it, it only answered the first ^C.

  • FIXED: Print and link the column of a source location counting from 1.
    The column of a syntax error and of the hyperlinks we emit for a
    location was taken from the line_position of the stream, which
    counts from 0, while the C compiler, ripgrep, editors and edit/1 all
    count the first column as 1.

  • ADDED: shell_command/1: find the preferred interactive shell executable.

  • PORT: #1514 Windows: make sure PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
    is defined.

  • FIXED: library(prolog_xref): track prolog_listen/2 properly.
    Created called heads with arity 0, as in p() rather than p.

  • ADDED: ls/1: tag links with @

  • DOC: Include library(shell) into the documentation.

  • MODIFIED: library(www_browser): use desktop_open/2 from library(desktop)
    If library(desktop) is available, www_open_url/1 now lets the desktop
    open the URL rather than searching for a browser itself. On Windows
    we use win_shell/2 if library(desktop) is not available.

Package clib

  • FIXED: sockets are inherited by processes we start A socket that lacks
    FD_CLOEXEC goes to every process we exec. A child that inherits a
    listening socket keeps its port in use for as long as it lives, so
    an HTTP server does not come back after a restart, and the child may
    accept connections meant for us. Prolog streams get the flag from
    Snew(), but a socket is a plain OS handle until it is turned into a
    stream, and a server socket never is.

  • ADDED: library(desktop): desktop_open/1,2 to open a file, directory
    or URL desktop_open/1,2 hands a document over to the application the
    desktop associates with it, e.g., a PDF viewer for a .pdf file or a
    file browser for a directory. It uses the Windows ShellExecute() API,
    open on MacOS and one of xdg-open, gio, kde-open,
    etc. on other systems. The Prolog flag desktop_opener and the
    option opener(Command) allow selecting the command explicitly.

  • ENHANCED: process_create/3: detached(true) no longer waits for the
    process If detached(true) is used without process(PID) and without
    pipes, process_create/3 now returns as soon as the process is started
    instead of waiting for its completion. On POSIX systems this uses
    a second fork(), such that the process is inherited by init and
    we do not have to reclaim it. On Windows we close the process and
    job handles.

Package http

  • FIXED: HTML rendering of url/2 message elements The HTML message
    renderer passed the URL of an url/2 element straight into href, which
    raises a type error if it is a File:Line source location rather than a
    web link, and it wrote the label as-is, which is wrong now that a label
    may be a Format-Args pair or an ansi/3 term. Labels are now rendered to
    text and a source location prints as text rather than as a broken link.

Package libedit

  • FIXED: a prompt the program wrote itself was lost on a redraw A read
    that starts where the output left the caret has no prompt of its own:
    format("name: "), read_line_to_string(user_input, S)' puts those six columns on the screen as ordinary output and then reads. libedit is handed an empty prompt and takes the line to start in column 0, six columns to the left of where it does. While it moves the caret relatively that goes unseen, but a full refresh -- a SIGWINCH, a resize it notices at a keypress, ^L -- redraws the input over name:
    ’ and leaves the caret six columns out.

  • ADDED: OSC 133: mark the end of the output and a continuation prompt
    The prompt, the input and the start of the output were marked; where
    the output ended was left for the reader to guess from the prompt
    after it, and a term typed over several lines was marked as several
    commands because every line got the mark that starts one.

  • ADDED: el_set/2 and el_get/2 prompt_marks(Boolean) Turns the OSC 133
    prompt marks off for a terminal that would print them rather than
    read them. They are on by default. The marks live in the prompt
    string, so setting the option throws the cached prompt away for
    update_prompt() to build again.

  • ADDED: mark the prompt and the input with OSC 133 While reading a
    line, surround the prompt and the input with the FinalTerm “semantic
    prompt” marks: A' before the prompt, B’ before the input and `C’
    when the line was entered. A terminal that reads them – Epilog,
    iTerm2, kitty, WezTerm, VS Code – can tell prompt, input and output
    apart, and so jump between prompts, act on the output of one command,
    or move the caret to a click in the line being edited.

  • FIXED: no bracketed paste while reading a single character Bracketed
    paste (DEC private mode 2004) says that a line editor owns the input.
    A read that asks for one character – get_single_char/1, the tracer
    at its `? ’ prompt, with_tty_raw/1 – is not such a read, so turn
    the mode off for its duration.

  • FIXED: resize of a wrapped input line missed when SIGWINCH is lost
    Resizing an Epilog window while editing a line that wraps could leave
    libedit painting on rows that hold something else: the next key moved
    the caret by rows and columns computed from the width the terminal
    no longer had, and the repaint left a copy of the first row behind.

  • ENHANCED: Do not leave the input decoration on the rows libedit
    erases The toplevel decorates the line being edited by leaving the
    attributes of the colour class input in effect while the user
    is typing. If that class has a background colour, the rows libedit
    erases because the line got shorter were painted with it and stayed
    that way: unwrap a long line or move from a multi-line history entry
    to a shorter one and a coloured bar was left below the line.

  • FIXED: Do not decorate completions and incremental search as input
    The toplevel decorates the input line by leaving the attributes of the
    colour class input in effect while the user is typing. The completion
    alternatives and the incremental search prompt are written while these
    are active, so they were coloured as input. Worse, input may have
    a background colour, which the \e[0K' used by the search prompt then paints to the right margin. Both now reset the attributes first; the redisplay’ that ends these commands re-installs the decoration.

  • FIXED: honour a PL_dispatch() exception before reading the terminal
    The PL_RAWTTY/PL_NOTTY branch of Sread_libedit() ignored the result
    of PL_dispatch() and blocked in read(2), so an exception raised by a
    signal or an event callback was only noticed after the user typed a
    character. Hand it to the stream instead, as read_char() already does.

  • FIXED: Windows: do not report a modifier key press as a NUL character
    Windows queues a key-down event for the modifier of every combination
    typed. Reporting it to libedit as a character handed it a NUL.
    For ^C that NUL was answered to the interrupt handler’s “Action (h
    for help) ?” prompt, which printed “Unknown option” before the user
    had touched a key. See swipl-devel issue #1515.

Package ltx2htm

  • FIXED: Spacing of infix operators in term description items A comma
    binds to the left operand and is followed by a space. Rendering it
    with a symmetric separator turned e.g. the ansi_format/3 attributes into
    fg(Color) , bg(Color),hfg(Color),hbg(Color). Replaces nospace_op/1
    with op_spacing/4 and adds the LaTeX \infixopsep{Op} to do the same
    for the printed manual.

  • FIXED: Preserve spaces around single and back quotes The LaTeX tokenizer
    classifies ' and ` as words. As spaces between two adjacent
    words are dropped on input and regenerated on output this loses the
    spaces around them: the translation turns the quotes into the HTML
    entities &lsquo; and &rsquo; and such command tokens do not take
    part in the regeneration. Tokenize the quotes as TOK_NOSPACEWORD
    such that the surrounding spaces are preserved in the token list.

Package pengines

  • FIXED: HTML rendering of url/2 message elements The HTML message
    renderer passed the URL of an url/2 element straight into href, which
    is wrong if it is a File:Line source location rather than a web link,
    and it wrote the label as-is, which is wrong now that a label may
    be a Format-Args pair or an ansi/3 term. Labels are now rendered to
    text and a source location prints as text rather than as a broken link.

Package pldoc

  • FIXED: Spacing of infix operators in term description items
    A comma binds to the left operand and is followed by a space.
    Adds \infixopsep{Op}, used by \infixterm and \infixtermitem, which
    also keeps a module qualifier free of surrounding spaces.

Package xpce

  • FIXED: print dialog proposed a printer queue named postscript' When $PRINTER is not set, <-print_command_template now proposes plain ``lpr``, letting lpr(1) pick the default queue, rather than expanding %p to the bogus queue name postscript’. That name was also a leftover
    from printing PostScript.

  • FIXED: resources referring to .png icons that were replaced by .svg
    Several libraries still referred to 16x16 and 32x32 .png icons that
    were removed when the development tools moved to .svg. Notably,
    this made the PceEmacs buffer menu fail to open.

  • MODIFIED: print graphics as PDF rather than PostScript
    graphical<-postscript and class win_printer are gone, leaving
    both library(print_graphics) and PceDraw unable to print. Both now
    render to a temporary PDF file and hand that to the print spooler.

  • REMOVED: PceDraw and grapher Windows metafile support Class
    win_metafile and display->selection_owner no longer exist
    and the clipboard handles text only, so none of this can work.
    Removes the PceDraw clipboard menu with its ->export_win_metafile
    and ->import_win_metafile, the draw_metafile shape and
    grapher->copy_graph.

  • FIXED: PceEmacs C mode: GDB commands called a non-existing method The
    method is ->tell_gdb_warn; only ->break_at_line used the right name.

  • FIXED: calls to the deleted graphical->synchronise Both callers
    only wanted the pending changes to become visible, which is what
    window->flush does.

  • FIXED: the Dialog Editor used the deleted display<-visual_type
    Colour is now always available, so the monochrome alternatives and
    the ifcolour/2 helper selecting between them are dropped.

  • FIXED: PceEmacs buffer menu and Dialog Editor used deleted frame
    methods frame<->icon and frame<->icon_label were deleted,
    but two callers were missed. As a result, opening the PceEmacs buffer
    menu reported an error and failed to create the window.

  • FIXED: crash when ->initialise fails on a class with non-slot C fields
    Instance prototypes initialise the declared slots only, leaving C fields
    such as file.fd filled with uninitialised memory. As a failed
    ->initialise still sends ->unlink, new(_, file(SomeFileObject))
    crashed in Sclose().

  • ENHANCED: Epilog: toggle fold_previous from the Settings menu Added
    a marked “Fold previous command” item to the Settings submenu that
    toggles the fold_previous setting of the current terminal. As with
    the Debug menu items, a condition updates the mark from the terminal
    state each time the menu is opened.

  • FIXED: Epilog: a window row is not a buffer line under a closed fold
    Writing below a closed fold scrolled the window although it had room
    for the caret still, taking what was above the fold off the top,
    and a client that placed its caret with CUP landed in the text the
    fold hides, where what it wrote next never showed. Both counted
    lines where the window counts rows.

  • FIXED: Epilog: the alternate screen over a closed fold Entering the
    alternate screen saved one line per row of the window, but a closed
    fold hides lines the window does not show and the erase that follows
    takes those away too: what came back after e.g. help/0 was the text
    the fold hid, with everything below it gone. The window is now saved
    in the lines its rows cover, and the blocks that name them stay while
    the application owns the window, so the folds close again over the
    text that comes back.

  • TEST: terminal: wait for the echo of a repeated command The fixed
    pause was never long enough on Windows, where the input reaches the
    client over a pipe a character to the dispatch round.

  • FIXED: terminal: let go of a block whose end was erased An erase takes
    the lines below the caret and leaves the ones above, so a block can
    keep its prompt and lose the mark that closed it. It can no longer
    say how far it reaches, but rlc_sweep_blocks() kept it as long as one
    anchor was live and ED 0 did not sweep at all. Windows hit this on
    every ^L: libedit’s built-in termcap clears the screen with CUP home +
    ED 0, and the stale blocks broke terminal_blocks.

  • TEST: terminal: a C0 control around an OSC 133 mark is not printed

  • FIXED: terminal: ignore unhandled C0 control characters Characters
    below 0x20 that have no VT100 meaning were rendered as glyphs.
    A bash PS0 carrying readline’s […] markers, for example, makes
    bash emit \001 and \002 verbatim before every command’s output.
    Real terminals discard such controls.

  • ENHANCED: Use ->opacity to grey out an inactive terminal.

  • ADDED: terminal_image ->input_focus: bool Handling the keyboard
    focus is now a method of its own rather than inline code in ->event,
    allowing subclasses to react on gaining or losing the focus.

  • TEST: terminal: a prompt the program wrote survives a resize Resize
    while a read that started where the output left the caret is pending,
    and check that the row is unchanged, that the caret stayed put and
    that ^A goes to the start of the input rather than to column 0.

  • TEST: terminal: dump the screen when the no-prompt click misses
    click_moves_the_caret_without_a_prompt asserted the caret column with
    a bare comparison, which says 4=:=10' and nothing about how the caret got there. It is the one caret assertion in the suite a redraw can move: the prompt is the program's own output, so libedit takes the line to start at column 0, and a full refresh paints the input over name: ’ and leaves the caret six columns to the left of the click.
    assert_cursor/3 reports the row and the screen, on which that is plain.

  • TEST: terminal: sample the terminal rather than the frame chrome
    term_screenshot/2 read the top 41 pixel rows of `frame <-image’,
    where the Epilog menu bar sits: the terminal starts 38 pixels down.
    Every shot therefore sampled the same unchanging chrome, two
    shots compared equal whatever the terminal was told to paint, and
    terminal_attributes failed on each of its “must differ” assertions
    from the day it was added.

  • ADDED: Epilog: hide and show the output of every command from the
    menu The menu of a fold marker gains Hide/Show all outputs, and Remove
    moves up beside the folding it belongs with.

  • ADDED: the xpce_defaults flag: decline the user’s Defaults file
    XPCE read the class variable defaults on the first lookup of a class
    variable, wherever in the program that happened to fall, and read the
    file belonging to whoever was running it along with them. A test suite
    or an application that must not depend on the preferences of its user
    had no way to say so: by the time it could speak they had been read.
    This is not hypothetical – a terminal test failed here because the
    author had turned a mode on in his own Defaults.

  • ADDED: Epilog: close the previous command as one is entered Reading an
    OSC 133 mark was a static function with nowhere to put a policy, and the
    policy this wanted is not the terminal’s. It becomes ->prompt_mark,
    sent from the OSC decoder as ->window_label and ->working_directory
    already are, with the letters decoded to what they mean here: where
    a prompt starts, where the line the user edits starts, where that
    line was entered and its output begins, and where the output ends.
    The default implementation is what read them before.

  • ADDED: terminal_block->remove: take a command out of the buffer
    Folding hides the output of a command; this takes the whole of it away.
    The lines it covers go and the text under them moves up into the gap,
    which for an input typed over several lines is all of them at once –
    they are one block, so they go as one.

  • ADDED: Epilog: act on the command the mouse or the caret is on The
    terminal knows what its window has been used for; this is what it
    takes to reach that. Right-clicking a command offers to copy it,
    to copy what it printed, or to hide that output; \C-\S-h folds the
    command being edited, and \C-\S-<cursor_up> and \C-\S-<cursor_down>
    walk the prompts, as terminals with shell integration do.

  • ADDED: Epilog terminal: commands as terminal_block objects, and
    folding The OSC 133 marks were read for the one thing the mouse needed
    and thrown away. They say more: A' is where a prompt starts, B’
    where the line the user edits starts, C' where it was entered and the output begins, and D’ where that output ends. Kept, they are
    a model of what the window has been used for, and <-blocks hands it
    over as a chain of terminal_block objects, oldest first.

  • FIXED: xpce terminal: XPCE_TERM_TRACE printed the wrong parser state
    The name table in rlc_putansi() still held the seven states of an older
    ansi_state, in the wrong order, so every trace line past CMD_ESC named
    a state the parser was not in. It now lists all twelve in enum order.

  • FIXED: xpce terminal: ESC > (DECKPNM) left the keypad in application
    mode Both ESC = and ESC > set app_keypad_mode to true, so leaving
    application keypad mode never took effect. Nothing reads the flag yet,
    which is why this went unnoticed.

  • FIXED: xpce terminal: enabled the ptsname() NULL check
    rlc_open_pty_pair() passed the result of ptsname() straight to strncpy()
    because the guard against it returning NULL sat in an #if 0. The name
    it reports, NAME_cannotPtsname, is already in the generated table,
    so the check only had to be turned back on.

  • CLEANUP: xpce terminal: removed the dead Windows-console API terminal.h
    still declared the plterm.dll console interface the emulator grew out
    of: the RlcHook typedefs and their setters, rlc_read/write/ close,
    getch/kbhit, ScreenCols/ScreenRows, the line-edit and completion
    structs, the history ring buffer and the lqueued/user_data types.
    None of it was ever defined. With them go the five LINE-READ SUPPORT
    functions in terminal.c that had no callers, rlc_caret_forward()
    which only rlc_goto_mark() used, the rlc_data fields for colours and
    scrollbar state that ti-> and the palette replaced, and the unused
    GWL_DATA, IMODE_
    and OPT_* macros – the last two also shadowed the
    OPT_SIZE enum of SWI-Prolog.h.

  • FIXED: xpce terminal: a second terminal took the palette Colours with
    it A terminal resolves the colour cube and the 24 bit colours of its
    client to Colour objects and holds them in its palette between paints.
    It held them with ->lock_object, whose F_LOCKED is a flag rather than
    a count, while ws_pixel_to_colour() hands every terminal that resolves
    an RGBA value the same interned Colour. The first terminal to go
    therefore took the protection of all the others with it: deleting a
    second Epilog window freed a Colour the first still had in its palette,
    and the next paint that used that colour handed r_clear() a Colour
    that was gone. Which is a crash in r_set_fill_fgbg(), as reported.

  • TEST: terminal: a click with nothing to say a line is being edited
    Exercises el_set/2 prompt_marks(false): with the marks and bracketed
    paste both off the client says nothing about the line it is editing,
    and the caret stays where it is.

  • ADDED: Epilog terminal: read the OSC 133 semantic prompt marks A client
    that marks its prompts says outright what the terminal could until now
    only guess: between B' and C’ there is a line being edited, and `B’
    landed where it starts. That is what a click needs to know before
    it asks the client to move its caret there, and a click in front of
    the input now stops at the input rather than walking into the prompt.

  • FIXED: Epilog terminal: click sent cursor keys at a single char read
    A click in the line being edited asks the client to move its caret, by
    sending as many cursor keys as there are grapheme clusters in between.
    A client that reads a single character has no caret to move and
    answers with the ESC of the first of them: clicking the source link
    in a port message of the command line tracer made it print “Unknown
    option (h for help)”.

  • TEST: run the terminal resize tests with SIGWINCH held back
    EPILOG_NO_SIGWINCH keeps rlc_resize_pty() from raising the signal
    on the client thread, which leaves libedit where a Windows console
    always is and where a lost signal puts us: with nothing but the size
    on the pty to go on. That is the path the three resize tests that
    press a key were failing on about one run in five, and the only way
    to reach it deliberately.

  • FIXED: xpce: crash when the window system has no display On a machine
    where SDL_Init() fails – headless, or no DISPLAY – xpce loads without
    a display object and `new(F, frame(hello))’ then stored a display
    that is not there. Reading it crashed the process, in ->create, in
    <-display, or in the first window that wanted its default colours.
    Say it instead: with no display there is no frame, and no window either.

  • TEST: move the alternate screen background erase test to the bce suite
    It belongs with the other background colour erase tests, and it runs
    there without a pty and without libedit: the whole file takes a second,
    where the terminal suite is off unless asked for. Reading pixels is
    still the only way to see the painted tail, so the window is sized
    to its terminal and the test lets the paint happen before it samples.

  • FIXED: xpce: a freed colour left a dangling entry in @rgba A Colour
    registers itself in @colours, by name, and in @rgba, by its encoded
    RGBA value. Both hold their members with refer' none, so neither keeps the Colour alive, but ->unlink only took the @colours entry out. The @rgba entry then pointed at memory that had been handed out again, and the next lookup of that colour value returned it: Image <-pixel’
    does one per pixel it reads, `Colour <-lookup’ one per new/2 on a colour
    with an RGB value, and the terminal one per palette slot it resolves.
    This crashed the xpce terminal test suite in about half of its runs.

  • FIXED: Epilog terminal: background colour erase lost over the alternate
    screen The full-line background of the input lines disappeared after
    help/1, and only the text kept its background. The tail of such a
    line is painted from the background colour erase (bce) that `\e[K’
    records on the line rather than from cells, and rlc_copy_line()
    did not carry that record along when smcup saved the screen.

  • FIXED: Epilog: warning when inserting a non-ASCII character Typing a
    character above 127 into a terminal_image, e.g. using the Unicode symbol
    picker, reported “Cannot construct 1-th argument for ->insert_self”.
    The key binding maps any character >= 128 to ->insert_self and fills
    the argument from the event id, which requires the declared type to
    include char or event_id. terminal_image declared it as the int
    range “0..”.

  • ADDED: Epilog terminal: a double-clicked word is matched as a word
    Picking a word with a double click says to look for that word, not for
    the letters it happens to be made of: a double click on Bar' passes over Barn’ while dragging over the same three characters does not.
    It also makes a one-character word worth looking for, which a single
    character picked any other way is not. A search seeded from such
    a selection with ^S or ^R keeps it; one started with \C-\S-f has no
    selection to take it from.

  • ADDED: Epilog terminal: ^S and ^R search on from the selection With
    a selection whose other occurrences are highlighted, ^S and ^R start
    an incremental search for what it holds, from where it is, and step
    to the next resp. previous match at once – so the matches that are
    already lit up are the ones they walk. From there it is the ordinary
    search: repeats, Backspace to widen, M-c and M-w, Escape to leave the
    hit selected. ^G gives back the view and the selection the search
    started from, so a search one did not mean to start costs nothing.

  • ADDED: Epilog terminal: highlight the other occurrences of the selection
    Selecting text in an Epilog terminal now says what to look for as well
    as what to copy: the other places the selected text occurs on the page
    are painted in <-isearch_other_style, the way the other matches of an
    incremental search are, and the bar reports which of them the selection
    is and how many there are, as `Selection: Bar (1/5)'. Picking out
    a variable or an atom finds the rest of them without typing it again.

  • TEST: terminal: sync with the client before handing out a new terminal
    The first test of a unit could find the prompt back on top of what
    it painted: the window sends the client a SIGWINCH while it is still
    settling on its size, and the client answers that with a redraw of
    its input line. Neither wait_for_prompt/1 nor wait_settled/1 covers
    that redraw – it paints the prompt where the prompt already is,
    so it leaves the screen exactly as it found it.

  • TEST: terminal: check that SGR attributes select a font New unit
    terminal_attributes. It paints the same glyphs wrapped in each
    SGR sequence, samples the window through the new term_screenshot/2
    primitive and compares the samples: two shots of the same text differ
    exactly when it was painted in a different font, so the test need
    not know which font the painter chose.

  • ENHANCED: terminal: render italic text (SGR 3) The terminal now draws
    italic (SGR 3) text in a slanted font and turns it off again on SGR
    23, and combines italic with bold. Epilog claims to be an xterm,
    whose terminfo advertises sitm/ritm, so programs were already sending
    the sequence and it was being dropped.

  • ENHANCED: class style: added ->italic and <-italic A style can now
    ask for slanted text through an attribute, the way it already asks
    for bold, instead of having to name an italic font in its ->font slot.

  • FIXED: class style: setting a second attribute had no effect A style
    that already carried one of ->bold, ->highlight, ->grey or ->hidden
    silently ignored requests to set or clear another one.

  • FIXED: build on Linux: O_CLOEXEC undeclared in the xpce terminal The
    pty code asks for _XOPEN_SOURCE 600 to get the pty API, and glibc
    hides everything newer than POSIX 2001 once that macro is set by hand,
    O_CLOEXEC among it. The close-on-exec flags added by the previous
    commit therefore did not compile on Linux. MacOS declares the symbol
    at any level because this file also defines _DARWIN_C_SOURCE,
    which is why it went unnoticed.

  • FIXED: shell of an Epilog window survives halting Prolog The
    pty descriptors were inherited by every process the client starts.
    The client hands its own three to a shell of shell/0 or process_create/3
    as stdin, stdout and stderr, and those it is welcome to, but a copy of
    the master is another matter: as long as the child holds it, closing our
    side is not the last reference and the pty never hangs up. The shell
    is then never sent the SIGHUP that closing the master owes it, and it
    stays behind, holding whatever else it inherited, after Prolog is gone.

  • FIXED: epilog: describe this terminal to the programs that run in it
    Epilog claims to be an xterm compatible terminal by setting TERM,
    but left TERM_PROGRAM at the value it inherited from the terminal
    it was started from, and run_shell/0 let the shell inherit both.
    Programs run from an Epilog window or its shell therefore applied the
    quirks of that other terminal to ours. Notably ansi_get_color/2 does
    not query a terminal that says it is Apple_Terminal, so no program
    started from an Epilog window could find out the colours of the window
    it runs in, which is what library(theme/auto) uses to pick a theme.

  • FIXED: terminal: paint the erased tail of a line with the background
    (bce) ESC [ K (Erase in Line) dropped the cells to the right of
    the caret rather than painting them with the background colour that
    is in effect. As a result a coloured block, such as the striped
    answers of the interactive toplevel, only covered its own text and
    stopped short of the right margin.

  • FIXED: destroying a frame leaked the backing store of its windows
    unlinkFrame() uncreated the frame before it freed its members, but
    ws_created_window() is false from the moment the frame is uncreated.
    uncreateWindow(), reached from freeObject() on each member, therefore
    skipped ws_uncreate_window() and leaked the Cairo backing surface
    and the WsWindow of every window of every destroyed frame.

  • FIXED: SDL: dangling pointer to the window holding the pointer
    grab grabbing_window held a bare pointer, so a window that grabbed
    the pointer and then destroyed itself – Epilog’s “Halt Prolog”
    menu item does exactly that – was unallocated while the event loop
    still referred to it. Hold a code reference as we do for the mouse
    tracking window, which also makes the F_FREED test a valid read,
    and report the recovery under DEBUG(event) rather than on the console.

  • FIXED: Epilog: “Halt Prolog” when Epilog runs inside a Prolog toplevel
    The menu item asserted quit_requested/0, which is only examined
    by ep_wait__/0, i.e., when Epilog is the main goal. Started using
    epilog/0 from a running Prolog there is no such loop and the item
    did nothing. Track whether ep_wait/1 is active in ep_main_running/0
    and call halt/0 directly if it is not.

  • FIXED: gcc -Wstringop-truncation warning on MacOS and FreeBSD. The path
    fields of the OS structs used to find the working directory of the
    foreground process are fixed size arrays that need not be terminated.
    Bound the copy by the field size and fail if the path does not fit
    rather than returning a truncated one.

  • ADDED: Epilog profile/2: a profile/1 option to refine another profile.
    A profile that gives profile(Super) takes Super’s options for the ones
    it does not give itself, so a profile can be a shell in a particular
    directory or a toplevel with a particular background without repeating
    what it inherits. This is the option epilog/1 already takes to pick
    a profile, now meaningful in a profile of its own.

  • ADDED: epilog/1: inject(Spec) option to type at a new terminal.
    Spec is an item or a list of items. A string is typed as a line of
    text, any other item as a Prolog goal, using ->inject. As we cannot
    tell whether the terminal runs a shell or Prolog, the caller says so
    by choosing the type.

  • ADDED: xpce timer ->start: number of times to fire, and <-times.
    A timer started as ->start(repeat, N) fires N times and goes idle.
    <-times is what is left of that, counted off before the message runs,
    so a message that sees 0 knows it was the last one and may start the
    timer again, as it may for a `once’ timer. Without the argument a
    timer repeats as before.

  • FIXED: xpce terminal ->send: write to a pty we never opened or
    already closed. rlc_send() tested the master fd for non-zero.
    The struct is zeroed before the pty is opened, so “never opened”
    was caught, but rlc_close_connection() leaves -1, which passed the
    test and reached write(-1, …).

  • PORT: Make compile on MacOS again.

  • FIXED: Epilog and PceEmacs: the column of a source location
    counts from 1. Clicking a link with a column, e.g., produced by
    rg --hyperlink-format=file://{path}#L{line}:{column}, placed
    the caret one character to the right, as the line_pos of an xpce
    source_location counts from 0 while edit/1 and the tools that emit
    such links count from 1. Epilog now also accepts the #L<line>
    form used by GitHub and rg.

  • FIXED: xpce terminal: a coloured hyperlink label kept the colours
    of its client. The link_style colours now only apply to cells
    for which the client did not select a colour itself. A client that
    colours its links, e.g., rg --hyperlink-format=..., had its colours
    replaced by the link style. The underline of the link style still
    marks the link, and the link_armed_style used while hovering keeps
    replacing the colours: that is transient feedback which must show on
    a coloured link as well.

  • MODIFIED: PceEmacs File/Shell now starts a shell in an Epilog window.

  • FIXED: xpce terminal: translating a click to a cell was one cell off.
    Clicking the last character of a hyperlink did not open it and clicking
    the cell before it did, as the pixel of a click was mapped to the
    cell boundary at or after it rather than to the cell containing it.

  • FIXED: xpce terminal: process escape sequences inside an OSC
    8 hyperlink. An OSC 8 hyperlink is a state rather than a self
    contained sequence: the label between ESC ] 8 ; <params> ; <URL> ST and the same sequence with an empty URL is ordinary output that
    may carry SGR sequences. We used to collect the label as text, so
    a client that colours its links, e.g., rg --hyperlink-format=...,
    painted the escape sequences on the screen. Parameters such as id=
    are now accepted as well.

  • ADDED: library(epilog): profiles for new terminal windows. A profile
    is a named set of options for epilog/1. The built-in profiles are
    prolog, which runs the Prolog top level, and shell, which runs an
    interactive OS shell in the terminal. New and split windows inherit
    the profile and start in the working directory reported by the window
    they were created from. Profiles are added using the multifile hook
    epilog:profile/2.

  • ADDED: xpce terminal_image <-working_directory, <-foreground_directory
    and <-host A client that reports its directory using OSC 7 (ESC ] 7 ;
    file://host/path ST), which shells emit from their prompt hook, or
    using OSC 9;9, the Windows spelling, now updates <-working_directory
    and <-host. <-foreground_directory instead asks the OS where
    <-foreground_process is, which needs no cooperation from the client,
    but only works on Linux, macOS, FreeBSD, NetBSD and Solaris.

  • FIXED: terminal: pass Ctrl+Z to a process running in the terminal
    Ctrl+Z was dropped unconditionally, so a shell started on a terminal
    could not suspend its jobs.

  • FIXED: Ctrl+, Ctrl+], Ctrl+^ and Ctrl+_ to produce a control character
    These keys were passed on as the plain punctuation character, so a
    program running in a terminal could not be sent SIGQUIT with Ctrl+.

  • FIXED: terminal: clear(1) left the old screen behind ED 3 (erase saved
    lines) rebased the ring on slot 0 when the window was already empty,
    but left the text of those slots and the caret where they were, so
    the screen came back with old content. `clear’ sends ED 2 before ED
    3 and hit exactly that.

  • ADDED: epilog:profile/2 Multifile hook. This hook can be used to
    define new Epilog profiles. For example epilog:profile(shell, [title('Shell'), goal(shell)]).

  • ADDED: epilog: a bar over the terminal for messages and search options
    The incremental search says what it is looking for, how many there
    are and whether it found anything; until now nothing in an epilog
    window could show that. Its frame has no reporter, so the ->report
    calls already there – the ones the font commands make – went nowhere.

  • ADDED: terminal_image: Emacs style incremental search on Ctrl-Shift-F
    Type and the terminal highlights what it finds and scrolls to it.
    ^S and ^R walk the matches, backspace widens the search again, ESC
    leaves the hit where it is and ^G gives back the view the search
    started from. As in class editor, a focus function sits in the way
    of ->typed and sees every key until the search ends.

  • ADDED: terminal_image: search the buffer with <-find <-find, <-length
    and <-contents address the terminal’s buffer as a flat sequence
    of characters, and ->selection and ->scroll_to take an index in
    that same space, so a hit can be highlighted and brought into view.
    <-find follows text_buffer<-find in its arguments, its defaults and
    in failing rather than raising when there is no match.

  • ADDED: epilog/1: option background(Colour).

  • ADDED: epilog/1: option goal_split(Goal) to determine the goal to
    run in a new splitted terminal.

  • MODIFIED: Class terminal_image: first try to process Shift-Ctrl-Key
    or Gui-Key as accelerator

  • TEST: terminal: wait for the shell of shell/1 to be reading
    start_interactive_shell/1 slept a second and hoped; it now waits for
    the shell’s prompt. What is typed next then reaches a shell that
    is reading, and ^D in particular is no longer lost: on an empty line
    it is end of input to the line discipline, which hands it to whoever
    reads next as a zero-length read. A shell that has not put its own
    line editor on the terminal yet is not reading, and by the time it
    does the terminal is in raw mode, where the ^D the line discipline
    already consumed cannot come back.

Hi Jan. I reported the atom-GC bug, and I’m happy to report that 10.1.14 runs my code with no issues. (8 cores, as many threads, 100s of long-lived engines accessed from multiple threads, tabling, workloads lasting 15-20 minutes). As always, thank you for your attention and quick responses to issues and bugs.