PreviousUpNext

15.4.1414  src/lib/x-kit/widget/edit/millboss-types.pkg

# millboss-types.pkg
#
# Types (and some code) in support of textpane modes like
#
#     src/lib/x-kit/widget/edit/fundamental-mode.pkg
#     src/lib/x-kit/widget/edit/minimill-mode.pkg
#
# This is another of those files full of datatypes which wanted
# so much to be mutually recursive that finally I gave up, merged
# the relevant files, and let them recurse to their heart's content.
#
# See also:
#     src/lib/x-kit/widget/edit/textpane.pkg
#     src/lib/x-kit/widget/edit/millboss-imp.pkg
#     src/lib/x-kit/widget/edit/textmill.pkg
#     src/lib/x-kit/widget/gui/guiboss-types.pkg

# Compiled by:
#     src/lib/x-kit/widget/xkit-widget.sublib


stipulate
    include package   threadkit;                                # threadkit                     is from   src/lib/src/lib/thread-kit/src/core-thread-kit/threadkit.pkg
    #
#   package ap  =  client_to_atom;                              # client_to_atom                is from   src/lib/x-kit/xclient/src/iccc/client-to-atom.pkg
#   package au  =  authentication;                              # authentication                is from   src/lib/x-kit/xclient/src/stuff/authentication.pkg
#   package cpm =  cs_pixmap;                                   # cs_pixmap                     is from   src/lib/x-kit/xclient/src/window/cs-pixmap.pkg
#   package cpt =  cs_pixmat;                                   # cs_pixmat                     is from   src/lib/x-kit/xclient/src/window/cs-pixmat.pkg
#   package dy  =  display;                                     # display                       is from   src/lib/x-kit/xclient/src/wire/display.pkg
#   package fil =  file__premicrothread;                        # file__premicrothread          is from   src/lib/std/src/posix/file--premicrothread.pkg
#   package fti =  font_index;                                  # font_index                    is from   src/lib/x-kit/xclient/src/window/font-index.pkg
#   package r2k =  xevent_router_to_keymap;                     # xevent_router_to_keymap       is from   src/lib/x-kit/xclient/src/window/xevent-router-to-keymap.pkg
#   package mtx =  rw_matrix;                                   # rw_matrix                     is from   src/lib/std/src/rw-matrix.pkg
#   package rop =  ro_pixmap;                                   # ro_pixmap                     is from   src/lib/x-kit/xclient/src/window/ro-pixmap.pkg
#   package rw  =  root_window;                                 # root_window                   is from   src/lib/x-kit/widget/lib/root-window.pkg
#   package rwv =  rw_vector;                                   # rw_vector                     is from   src/lib/std/src/rw-vector.pkg
#   package sep =  client_to_selection;                         # client_to_selection           is from   src/lib/x-kit/xclient/src/window/client-to-selection.pkg
#   package shp =  shade;                                       # shade                         is from   src/lib/x-kit/widget/lib/shade.pkg
#   package sj  =  socket_junk;                                 # socket_junk                   is from   src/lib/internet/socket-junk.pkg
#   package x2s =  xclient_to_sequencer;                        # xclient_to_sequencer          is from   src/lib/x-kit/xclient/src/wire/xclient-to-sequencer.pkg
#   package tr  =  logger;                                      # logger                        is from   src/lib/src/lib/thread-kit/src/lib/logger.pkg
#   package tsr =  thread_scheduler_is_running;                 # thread_scheduler_is_running   is from   src/lib/src/lib/thread-kit/src/core-thread-kit/thread-scheduler-is-running.pkg
#   package u1  =  one_byte_unt;                                # one_byte_unt                  is from   src/lib/std/one-byte-unt.pkg
#   package v1u =  vector_of_one_byte_unts;                     # vector_of_one_byte_unts       is from   src/lib/std/src/vector-of-one-byte-unts.pkg
#   package v2w =  value_to_wire;                               # value_to_wire                 is from   src/lib/x-kit/xclient/src/wire/value-to-wire.pkg
#   package wg  =  widget;                                      # widget                        is from   src/lib/x-kit/widget/old/basic/widget.pkg
#   package wi  =  window;                                      # window                        is from   src/lib/x-kit/xclient/src/window/window.pkg
#   package wme =  window_map_event_sink;                       # window_map_event_sink         is from   src/lib/x-kit/xclient/src/window/window-map-event-sink.pkg
#   package wpp =  client_to_window_watcher;                    # client_to_window_watcher      is from   src/lib/x-kit/xclient/src/window/client-to-window-watcher.pkg
#   package wy  =  widget_style;                                # widget_style                  is from   src/lib/x-kit/widget/lib/widget-style.pkg
#   package xc  =  xclient;                                     # xclient                       is from   src/lib/x-kit/xclient/xclient.pkg
#   package xj  =  xsession_junk;                               # xsession_junk                 is from   src/lib/x-kit/xclient/src/window/xsession-junk.pkg
#   package xtr =  xlogger;                                     # xlogger                       is from   src/lib/x-kit/xclient/src/stuff/xlogger.pkg
    #

    #
    package wt  =  widget_theme;                                # widget_theme                  is from   src/lib/x-kit/widget/theme/widget/widget-theme.pkg
    package evt =  gui_event_types;                             # gui_event_types               is from   src/lib/x-kit/widget/gui/gui-event-types.pkg
    package gts =  gui_event_to_string;                         # gui_event_to_string           is from   src/lib/x-kit/widget/gui/gui-event-to-string.pkg
    package ct  =  cutbuffer_types;                             # cutbuffer_types               is from   src/lib/x-kit/widget/edit/cutbuffer-types.pkg
    package gt  =  guiboss_types;                               # guiboss_types                 is from   src/lib/x-kit/widget/gui/guiboss-types.pkg

    package l2p =  screenline_to_textpane;                      # screenline_to_textpane        is from   src/lib/x-kit/widget/edit/screenline-to-textpane.pkg
    package p2l =  textpane_to_screenline;                      # textpane_to_screenline        is from   src/lib/x-kit/widget/edit/textpane-to-screenline.pkg

    package d2p =  drawpane_to_textpane;                        # drawpane_to_textpane          is from   src/lib/x-kit/widget/edit/drawpane-to-textpane.pkg
    package p2d =  textpane_to_drawpane;                        # textpane_to_drawpane          is from   src/lib/x-kit/widget/edit/textpane-to-drawpane.pkg
    package m2d =  mode_to_drawpane;                            # mode_to_drawpane              is from   src/lib/x-kit/widget/edit/mode-to-drawpane.pkg
    package g2p =  gadget_to_pixmap;                            # gadget_to_pixmap              is from   src/lib/x-kit/widget/theme/gadget-to-pixmap.pkg

    package b2p =  millboss_to_pane;                            # millboss_to_pane              is from   src/lib/x-kit/widget/edit/millboss-to-pane.pkg
    package a2c =  app_to_compileimp;                           # app_to_compileimp             is from   src/lib/x-kit/widget/edit/app-to-compileimp.pkg

    package a2r =  windowsystem_to_xevent_router;               # windowsystem_to_xevent_router is from   src/lib/x-kit/xclient/src/window/windowsystem-to-xevent-router.pkg

    package gd  =  gui_displaylist;                             # gui_displaylist               is from   src/lib/x-kit/widget/theme/gui-displaylist.pkg

    package pp  =  standard_prettyprinter;                      # standard_prettyprinter        is from   src/lib/prettyprint/big/src/standard-prettyprinter.pkg


    package err =  compiler::error_message;                     # compiler                      is from   src/lib/core/compiler/compiler.pkg
                                                                # error_message                 is from   src/lib/compiler/front/basics/errormsg/error-message.pkg

    package im  =  int_red_black_map;                           # int_red_black_map             is from   src/lib/src/int-red-black-map.pkg
#   package is  =  int_red_black_set;                           # int_red_black_set             is from   src/lib/src/int-red-black-set.pkg
    package idm =  id_map;                                      # id_map                        is from   src/lib/src/id-map.pkg
    package sm  =  string_map;                                  # string_map                    is from   src/lib/src/string-map.pkg

    package r8  =  rgb8;                                        # rgb8                          is from   src/lib/x-kit/xclient/src/color/rgb8.pkg
    package r64 =  rgb;                                         # rgb                           is from   src/lib/x-kit/xclient/src/color/rgb.pkg
    package g2d =  geometry2d;                                  # geometry2d                    is from   src/lib/std/2d/geometry2d.pkg
#   package g2j =  geometry2d_junk;                             # geometry2d_junk               is from   src/lib/std/2d/geometry2d-junk.pkg

    package dxy =  digraphxy;                                   # digraphxy                     is from   src/lib/src/digraphxy.pkg
    package bq  =  bounded_queue;                               # bounded_queue                 is from   src/lib/src/bounded-queue.pkg
    package nl  =  red_black_numbered_list;                     # red_black_numbered_list       is from   src/lib/src/red-black-numbered-list.pkg
    package slt =  screenline_types;                            # screenline_types              is from   src/lib/x-kit/widget/edit/screenline-types.pkg

    tracefile   =  "widget-unit-test.trace.log";

    nb = log::note_on_stderr;                                   # log                           is from   src/lib/std/src/log.pkg

herein

    package millboss_types                                                                      # 
    {
        Wakeup_Arg      =       gt::Wakeup_Arg;
        Wake_Me_Option ==       gt::Wake_Me_Option;

        Point_And_Mark                                                                          # 'Point' is the visible cursor.  'Mark' (if set) marks the other end of the selected region.  (Emacs nomenclature.)
          =
          { point:              g2d::Point,                                                     # Note that point and mark are per-textpane, not per-textmill. (This matters because there may be multiple textpanes open on one textmill).  This is different from emacs, where 'mark' is per-textmill.
            mark:               Null_Or(g2d::Point)                                             # NULL means the emacs-style 'mark' is not currently set.
          };

        Inport                                                                                  # Used to name mill input ports.
          =                                                                                     #
          { mill_id:            Id,                                                             # Id   of the mill.
            inport_name:        String                                                          # Name of the input port.
          };

        Outport                                                                                 # Used to name mill output ports.
          =                                                                                     #
          { mill_id:            Id,                                                             # Id   of the mill.
            outport_name:       String                                                          # Name of the output port.
          };

        Portpair                                                                                # Used to name watcher-watchee mill-pairs.
          =                                                                                     #
          { inport:             Inport,                                                         # Watcher.
            outport:            Outport                                                         # Watchee.
          };

        package inport_key {
            #
            Key = Inport;
            #
            fun compare
                  (
                    k1:         Key,
                    k2:         Key
                  )
                =
                case (int::compare ((id_to_int k1.mill_id), (id_to_int k2.mill_id)))
                    #   
                    GREATER =>  GREATER;
                    LESS    =>  LESS;
                    EQUAL   =>  string::compare (k1.inport_name, k2.inport_name);       
                esac;
        };

        package outport_key {
            #
            Key = Outport;
            #
            fun compare
                  (
                    k1:         Key,
                    k2:         Key
                  )
                =
                case (int::compare ((id_to_int k1.mill_id), (id_to_int k2.mill_id)))
                    #   
                    GREATER =>  GREATER;
                    LESS    =>  LESS;
                    EQUAL   =>  string::compare (k1.outport_name, k2.outport_name);     
                esac;
        };

        package millwatch_key {                                                                 # We use this to track which mill inports are watching which mill outports.
            #
            Key = Portpair;
            #
            fun compare                                                                         # This comparison is just for doing lookups,
                  (                                                                             # so we do the Int compares first because the are fast,
                    k1:         Key,                                                            # followed by the slow string compares (which we may
                    k2:         Key                                                             # thus avoid doing at all on most compares).
                  )
                =
                case (int::compare ( (id_to_int k1.inport.mill_id),
                                     (id_to_int k2.inport.mill_id)
                     )             )
                    #   
                    GREATER =>  GREATER;
                    LESS    =>  LESS;
                    EQUAL   =>
                        case (int::compare ( (id_to_int k1.outport.mill_id),
                                             (id_to_int k2.outport.mill_id)
                             )             )
                            #
                            GREATER =>  GREATER;
                            LESS    =>  LESS;
                            EQUAL   =>
                                case (string::compare (k1.inport.inport_name, k2.inport.inport_name))
                                    #
                                    GREATER =>  GREATER;
                                    LESS    =>  LESS;
                                    EQUAL   =>  string::compare (k1.outport.outport_name, k2.outport.outport_name);     
                                esac;
                        esac;               
                esac;
        };

        package ipm =  red_black_map_g(    inport_key );                                        # "ipm" ==  "inport_map".       red_black_map_g         is from   src/lib/src/red-black-map-g.pkg
        package ips =  red_black_set_g(    inport_key );                                        # "ips" ==  "inport_set".       red_black_set_g         is from   src/lib/src/red-black-set-g.pkg

        package opm =  red_black_map_g(   outport_key );                                        # "opm" == "outport_map".       red_black_map_g         is from   src/lib/src/red-black-map-g.pkg
        package ops =  red_black_set_g(   outport_key );                                        # "ops" == "outport_set".       red_black_set_g         is from   src/lib/src/red-black-set-g.pkg

        package mwm =  red_black_map_g( millwatch_key );                                        # "mwm" == "millwatch_map".     red_black_map_g         is from   src/lib/src/red-black-map-g.pkg
        package mws =  red_black_set_g( millwatch_key );                                        # "mws" == "millwatch_set".     red_black_set_g         is from   src/lib/src/red-black-set-g.pkg

        Millout                                                                                 # One output port for a mill.  This is a specialization of the Crypt type in src/lib/core/init/pervasive.pkg
          =                                                                                     # 
          { outport:            Outport,                                                        # Globally unique identifier for output port consisting of mill id + port name.
            crypt:              Exception,                                                      # The hidden value packed in an exception, taking advantage of the fact that Exception is Mythryl's only extensible datatype.  This hack lets code in millboss_imp, plugboard etc to process Millouts and Millins without importing all the underlying data types.
            #
            port_type:          String,                                                         # Type of the contents of the 'crypt' field, for debugging/inspection, e.g. "int_millout::Int_Millout"  for   src/lib/x-kit/widget/edit/int-millout.pkg
            data_type:          String,                                                         # Type of the values that flow through the stream, for plugboard.pkg,  e.g. "Int"                       for   src/lib/x-kit/widget/edit/int-millout.pkg
            info:               String,                                                         # Any added info about the data field, for debugging/inspection.  This compensates for Millout's lack of typesafety; it should include any information useful when debugging "Whoops, we got the wrong Millout here" bugs. Can be just the empty string.
            #
            counter:            Ref(Int)                                                        # Count messages sent through port, for debug/display purposes.
          };                                                                                    #

        Millin                                                                                  # One input port for a mill.
          =                                                                                     #
          { inport:             Inport,                                                         # Globally unique identifier for input port consisting of mill id + port name.
            port_type:          String,                                                         # Specifies which mill outputs may be connected to this mill input:  Must have Millout.port_type == Millin.port_type.
            mono:               Bool,                                                           # TRUE iff this Input can watch at most one Watchable.
            #                                                                                   #
            note_input:         Millout -> Void,                                                # For a MONO_INPUT this call will replace any previous setting;  for a POLY_INPUT this will add  the Millout to   the set of outputs read.
            drop_input:         Millout -> Void,                                                # For a MONO_INPUT this call will clear the input to NULL;       for a POLY_INPUT it will remove the Millout from the set of outputs read -- no-op if not present.
            #
            counter:            Ref(Int)                                                        # Count messages read through port, for debug/display purposes.
          };                                                                                    # 

        Millwatch                                                                               # Everything millboss knows about a case of one mill inport watching one mill outport.
          =
          { millin:             Millin,
            millout:            Millout
          };

        Graphic_Line_Prefix                                                                     # Support for drawing arbitrary mouse-sensitive graphics to the left of the line in   src/lib/x-kit/widget/edit/screenline.pkg
          =                                                                                     # Motivating example is planned plugboard.pkg support;  could also be used for conventional [+] vs [-] collapsable hierarchy display, say.
          { prefix_length_in_pixels:    Int,                                                    # This tells screenline.pkg how many pixels to indent the regular text for the line.
            prefix_draw_fn:             slt::Redraw_Fn,                                         # This tells screenline.pkg what to draw on the left-of-text space.
            prefix_click_fn:            slt::Mouse_Click_Fn                                     # This tells screenline.pkg what to do when user clicks on left-of-text space.
          };
        Monoline                                                                                # Monoline + Polyline are intended as support for foldingmode-style functionality where a visible screen line may represent either a single line of text or else an entire indented paragraph where only the first line is displayed.
          =                                                                                     #
          { string:     String,                                                                 #
            prefix:     Null_Or( Graphic_Line_Prefix )                                          #
          };                                                                                    #
        Polyline                                                                                # 
          =                                                                                     # 
          { line:       Monoline,                                                               # The visible line.
            more:       List(Monoline)                                                          # The currently-invisible lines, if any.
          };                                                                                    #
        Textline                                                                                #
          #                                                                                     #
          = MONOLINE Monoline                                                                   # The normal case -- folding isn't hiding anything.
          | POLYLINE Polyline                                                                   # The folded case -- folding is    hiding the 'more' part.
          ;                                                                                     #
        fun visible_line (MONOLINE { string, ... }) =>      string;                             # A little convenience function to get the visible line.
            visible_line (POLYLINE { line,   ... }) => line.string;                             #
        end;                                                                                    #
            

        Textlines = nl::Numbered_List( Textline );                                              # In textmill.pkg we store our file contents in this, line by line.

        fun findline                                                                            # A little convenience fn used heavily in files like   src/lib/x-kit/widget/edit/fundamental-mode.pkg
              (
                textlines:      Textlines,
                line_key:       Int
              )
            =
            {   line =  case (nl::find (textlines, line_key))
                            #
                            THE line => line;
                            #
                            NULL     => MONOLINE  { string => "\n",
                                                    prefix => NULL
                                                  };
                        esac;

                visible_line  line;
            };


        Textstate
          =
          { textlines:                  Textlines,                                              # Complete text contents of textmill.
            editcount:                  Int                                                     # Count of edits applied.  Intended to allow clients to quickly detect whether any changes have been made since they last polled us.
          };

        Undostate = Textstate;                                                                  # Synonym for readability.

        Edit_History = bq::Queue( Undostate );

        Pane_Info
          =
          { pane_id:                            Id,
            pane_tag:                           Int,                                            # We assign each pane a small positive Int tag to be displayed on modeline and used by "C-x o" (other_pane) in   src/lib/x-kit/widget/edit/fundamental-mode.pkg
            mill_id:                            Id                                              # Id for mill displayed in this pane.
          };

        Stage = INITIAL
              | MEDIAL
              | FINAL
              ;
        #
        Promptfor
          #                                                                                     # We should probably add POSITIVE_NUMBER and INTEGER cases here, for editfns like fundamental_mode::goto_line. XXX SUCKO FIXME.
          = STRING              { prompt: String,  doc: String }                                # String arg is the prompt to supply to user.
          | FILENAME            { prompt: String,  doc: String }                                # The critical difference between FILENAME    and STRING is that we can do tab-completion on FILENAME    based on reading directory contents.
          | MILLNAME            { prompt: String,  doc: String }                                # The critical difference between MILLNAME    and STRING is that we can do tab-completion on MILLNAME    based on list of all running mill microthreads.
          | COMMANDNAME         { prompt: String,  doc: String }                                # The critical difference between COMMANDNAME and STRING is that we can do tab-completion on COMMANDNAME based on list of all defined commands.
          | INCREMENTAL_STRING  { prompt: String,  doc: String }                                #
          ;
        
        fun promptfor_prompt  (STRING               r) => r.prompt;
            promptfor_prompt  (FILENAME             r) => r.prompt;
            promptfor_prompt  (MILLNAME             r) => r.prompt;
            promptfor_prompt  (COMMANDNAME          r) => r.prompt;
            promptfor_prompt  (INCREMENTAL_STRING   r) => r.prompt;
        end;

        fun promptfor_doc     (STRING               r) => r.doc;
            promptfor_doc     (FILENAME             r) => r.doc;
            promptfor_doc     (MILLNAME             r) => r.doc;
            promptfor_doc     (COMMANDNAME          r) => r.doc;
            promptfor_doc     (INCREMENTAL_STRING   r) => r.doc;
        end;

        Prompted_Arg
          #
          = STRING_ARG             { prompt: String, doc: String, arg: String }                 # 'arg' is the string read from user.  Other two are copied from Promptfor record.
          | INCREMENTAL_STRING_ARG { prompt: String, doc: String, arg: String, stage: Stage }   # An INCREMENTAL_STRING -- editfn gets called each time it changes, even though not yet complete.
#         | COMMAND_ARG
#         | FILENAME_ARG                                                                        # I'm not sure we'll need this -- any reason a filename can't be just a string at this point?
          ;

        Editfn_Out_Option                                                                       # This conveys information from editfns via textmill back to textpane.  These are basically the operations implemented by textpane for use by editfns in (e.g.)  src/lib/x-kit/widget/edit/fundamental-mode.pkg
          #
          = TEXTLINES                   Textlines                                               # Note revised contents of textmill.
          | TEXTMILL                    Textpane_To_Textmill                                    # Note that textpane is now open on a different textmill.
          | POINT                       g2d::Point
          | MARK                        Null_Or(g2d::Point)
          | LASTMARK                    Null_Or(g2d::Point)
          | SCREEN_ORIGIN               g2d::Point
          | READONLY                    Bool                                                    # Set textmill readonly flag to given value.
          | EDIT_HISTORY                Edit_History    
          | SAVE                                                                                # Save textmill contents to disk, if dirty.
          | QUIT                                                                                # This is intended to implement keyboard_quit  (normally bound to C-g) functionality in fundamental-mode.pkg.
          | STRING_ENTRY_COMPLETE                                                               # This is intended to implement input_complete (normally bound to RET) functionality in minimill-mode.pkg.
          | MODELINE_MESSAGE            String                                                  # Post a message (e.g., "No files need saving.") to the textpane modeline that will be visible until next keystroke is typed. 
          | EDITFN_TO_INVOKE            Keymap_Node                                             # Execute given editfn.  Supports (e.g.) query_replace -- this lets it read input from modeline and then continue.
          | QUOTE_NEXT                  Keymap_Node                                             # Dedicated support for C-q:  Insert next keystroke in buffer instead of interpreting as a command.
          | EXECUTE_COMMAND             String                                                  # Dedicated support for M-x:  Execute command with given name.
          | COMMENCE_KMACRO                                                                     # Dedicated support for "C-x (": commence_keystroke_macro.
          | CONCLUDE_KMACRO                                                                     # Dedicated support for "C-x )": conclude_keystroke_macro.
          | ACTIVATE_KMACRO             Int                                                     # Dedicated support for "C-x e": activate_keystroke_macro.  Int is repeat factor.

        also
        Textmill_Statechange                                                                    # Used to tell clients (mostly textpane.pkg) about changes in state of a textmill.  Textmills send these to all watchers -- this is how multiple textpanes can track a single textmill.
          #                                                                                     # 
          = TEXTSTATE_CHANGED   { was: Textstate,          now: Textstate         }
          | UNDO                { was: Textstate,          now: Undostate         }
          | FILEPATH_CHANGED    { was: Null_Or(String),    now: Null_Or(String)   }             # File being visited in the textmill.  Some textmills visit no file (in-memory editing only), hence the Null_Or.
          | NAME_CHANGED        { was: String,             now: String            }             # Name of textmill.  Every textmills has a globally unique name.
          | READONLY_CHANGED    { was: Bool,               now: Bool              }             #
          | DIRTY_CHANGED       { was: Bool,               now: Bool              }             #

        also
        Textmill_Option                                                                         # Optional args when creating a new textmill.
          #                                                                                     #
          =  MICROTHREAD_NAME   String                                                          # 
          |  ID                 Id                                                              # Stable, unique id for imp.
          |  INITIAL_FILENAME   String                                                          
          |  UTF8               String
          |  TEXTMILL_EXTENSION Textmill_Extension

        also
        Textpane_To_Textmill                                                                    # This is the port/handle a textpane uses to represent/control a textmill.
            =                                                                                   # 
            TEXTPANE_TO_TEXTMILL                                                                # 
              { id:                     Id,                                                     # Unique id to facilitate storing textpane_to_textmill instances in indexed datastructures like red-black trees.
                #
                get_maxline:            Void -> Int,                                            # Max currently valid line number.
                pass_maxline:           Replyqueue -> (Int -> Void) -> Void,
                #
                get_line:               Int -> Null_Or(String),
                pass_line:              Replyqueue
                                           -> Int
                                           -> (Null_Or(String) -> Void)
                                           -> Void,
                #
                set_lines:              List(String) -> Void,
                get_lines:              (Int, Int) -> List(String),
                pass_lines:             Replyqueue
                                             -> (Int, Int)
                                             -> (List(String) -> Void)
                                             -> Void,
                #
                get_textstate:          Void -> Textstate,                                      # 
                pass_textstate:         Replyqueue -> (Textstate -> Void) -> Void,
                #
                get_edit_result:        Edit_Arg -> Editfn_Out,
                pass_edit_result:       Edit_Arg                                                # This should be unused and can probably be eliminated -- it turns out that textpane needs to wait for result and update its state before invoking another editfn via textmill.
                                             -> Replyqueue
                                             -> (Editfn_Out -> Void)
                                             -> Void,                                           # 

                get_drawpane_startup_result:            Drawpane_Startup_Arg            -> Editfn_Out,
                get_drawpane_shutdown_result:           Drawpane_Shutdown_Arg           -> Editfn_Out,
                get_drawpane_initialize_gadget_result:  Drawpane_Initialize_Gadget_Arg  -> Editfn_Out,
                get_drawpane_redraw_request_result:     Drawpane_Redraw_Request_Arg     -> Editfn_Out,
                get_drawpane_mouse_click_result:        Drawpane_Mouse_Click_Arg        -> Editfn_Out,
                get_drawpane_mouse_drag_result:         Drawpane_Mouse_Drag_Arg         -> Editfn_Out,
                get_drawpane_mouse_transit_result:      Drawpane_Mouse_Transit_Arg      -> Editfn_Out,

                undo:                   Void -> Void,

                set_readonly:           Bool -> Void,                                           # 
                get_readonly:           Void -> Bool,                                           # TRUE iff textmill contents are currently marked as ineditable.
                pass_readonly:          Replyqueue -> (Bool -> Void) -> Void,

                set_textpane_hint:      Crypt -> Void,                                          # Store the current textpane's point+mark etc info on the textmill, so that if/when we open a new textpane onto this textmill, we can put the cursor in a sensible spot.
                get_textpane_hint:      Void -> Crypt,                                          # Using 'Crypt' spares textmill.pkg from needing to know about the relevant textpane.pkg types.

                                                                                                # The watcher protocol allows others imps (including other texteditors and also arbitrary application imps) to monitor changes to a given textmill.
                note__textmill_statechange__watcher                                             #  
                    :                                                                           #
                    ( Inport,                                                                   # Globally unique name for the watching port.
                      Null_Or(Millin),                                                          # This will be NULL if watcher is not another mill (e.g. a pane). Lets us pass Millin+Millout to millboss at same time, keeping millboss consistent.
                      (Outport, Textmill_Statechange) -> Void                                   # This fn is how we actually pass statechanges to watcher. The Outport arg lets a single watcher distinguish miltiple watchees.
                    )
                    -> Void,                                                                    #
                                                                                                #
                drop__textmill_statechange__watcher                                             #
                    :                                                                           #
                    Inport -> Void,                                                             # The Inport must match that given to note__textmill_statechange__watcher.
                    
                textmill_extension:     Null_Or( Textmill_Extension ),

                app_to_mill:            App_To_Mill                                             # Include the more general mill-agnostic interface.
              }

        also
        App_To_Mill                                                                             # This is intended to be an interface exported by all mills, not just textmills, to support operations which are generic across all mills.
            =
            APP_TO_MILL 
              { id:                     Id,                                                     # Unique id to facilitate storing textpane_to_textmill instances in indexed datastructures like red-black trees.
                millins:                ipm::Map(Millin),                                       # Get  Millins for this mill indexed by Inport.
                millouts:               opm::Map(Millout),                                      # Get  output streams available to watch.  Indexed by Outport.

                #
                get_dirty:              Void -> Bool,                                           # TRUE iff textmill contents are currently out of sync with diskfile contents.
                pass_dirty:             Replyqueue -> (Bool -> Void) -> Void,

                set_filepath:           Null_Or(String) -> Void,                                # Filepath controls what file textmill contents are read/written from/to.
                get_filepath:           Void -> Null_Or(String),                                # 
                pass_filepath:          Replyqueue -> (Null_Or(String) -> Void) -> Void,

                set_name:               String -> Void,                                         # Name uniquely identifies textmill to interactive user.
                get_name:               Void -> String,                                         # 
                pass_name:              Replyqueue -> (String -> Void) -> Void,

                reload_from_file:       Void -> Void,
                save_to_file:           Void -> Void,

                get_pane_guiplan:       Void -> gt::Gp_Widget_Type,                             # Synthesize a guiplan for a pane which will display the state of this mill.  This is primarily support for  switch_to_mill()  in  src/lib/x-kit/widget/edit/fundamental-mode.pkg
                pass_pane_guiplan:      Replyqueue -> (gt::Gp_Widget_Type -> Void) -> Void      # In general we do not want mills to know about GUI stuff (as a matter of clean layering and also to avoid package dependency loops) but we do want to have a way
                                                                                                # for a client to open up a GUI pane on an arbitrary mill, hence this call in the App_To_Mill interface.
              }

        # This port is implemented in:
        #
        #     src/lib/x-kit/widget/edit/millboss-imp.pkg
        #
        also
        Mill_To_Millboss                                                                        # This is the toplevel application code access pathway to texteditor functionality, and more generally pane/mill functionality.
            =                                                                                   # 
            MILL_TO_MILLBOSS
              {
                id:                     Id,                                                     # Unique id to facilitate storing mill_to_millboss instances in indexed datastructures like red-black trees.
                #
                get_textmill:           String       ->  Null_Or( Textpane_To_Textmill ),       # Get pre-existing textmill by name, return NULL if not found.
                make_textmill:          Textmill_Arg ->           Textpane_To_Textmill,         # Create new       textmill.  If there is a pre-existing one by the same name, modify given name to make new buffer's name unique.
                get_or_make_textmill:   Textmill_Arg ->           Textpane_To_Textmill,         # Get pre-existing textmill if one is found, create and return one if not found.
                get_or_make_filebuffer: Textmill_Arg -> String -> Textpane_To_Textmill,         # Find (or failing that, create) a textmill open on the given filepath.

                get_cutbuffer_contents: Void -> ct::Cutbuffer_Contents,                         # O(1) nonblocking.
                set_cutbuffer_contents: ct::Cutbuffer_Contents -> Void,

                note_pane:              { millboss_to_pane:     b2p::Millboss_To_Pane,          # Remember existence of a pane. Intended to support textpanes but also eventually other kinds of panes.
                                          mill_id:              Id                              # Mill displayed in pane.
                                        }                                                       #
                                        -> Void,                                                #

                drop_pane:              { pane_id: Id }         -> Void,                        # Forget   existence of a pane. Inverse of above.
                mail_pane:              (Id, Crypt)             -> Void,                        # Send something to a pane. If the pane is not yet registered with millboss, the crypt will be queued up and delivered when the pane registers. Used for linking up screenline.pkg instances to textpane.pkg instances at startup (etc).
                                                                                                # Using a Crypt here makes the mechanism general at a small cost in typesafety.  In particular, it buys us valuable modularity by keeping millboss from needing to know the types of the interfaces between textpane and screenline (etc).
                get_panes_by_id:        Void -> idm::Map( Pane_Info ),
                get_mills_by_name:      Void ->  sm::Map( Mill_Info ),
                get_mills_by_id:        Void -> idm::Map( Mill_Info ),
                    
                note_millwatch:         Millwatch -> Void,                                      # Take note of a new instance of one mill watching another.
                drop_millwatch:         millwatch_key::Key -> Void,                             # Undo previous.

                wake_me:                {                                                       # Used to schedule millboss_to_mill.wakeup calls.
                                          id:           Id,
                                          options:      List(Wake_Me_Option)
                                        }
                                        -> Void,

                app_to_mill:            App_To_Mill                                             # Include the App_To_Mill interface so that millboss can export a Millgraph Outport as a kinda-sorta mill itself. 
              }

        also
        Editfn_Node
          #
          = PLAIN_EDITFN        Plain_Editfn
          | FANCY_EDITFN                                                                        # Not currently useful.  Intended to support fns which need to do significant work in the context of textpane.pkg (vs textmill.pkg).  It may be about time to phase this out, in which case Editfn_Node and Keymap_Node can just merge.

        also
        Keymap_Node
          #
          = EDITFN              Editfn_Node
          | SUBKEYMAP           Keymap
          | UNDEFINED                                                                           # This is so we can mark a keystroke sequence as undefined even if an ancestor defines it.

        also
        Panemode_Initialization_Option                                                          # Returned by initialize_panemode_state() -- see below.
          #
          =
          INITIAL_POINT         g2d::Point

        also
        Panemode                                                                                # A panemode defines the semantics of a textpane. In particular, the keymap defines what editfns are invoked by what keystrokes.
            =                                                                                   # For a live example of Panemode see   src/lib/x-kit/widget/edit/fundamental-mode.pkg
            PANEMODE
              {
                id:                     Id,
                name:                   String,
                doc:                    String,
                #
                keymap:                 Ref( Keymap ),                                          # The keybindings for this mode, mapping for example "C-f" to forward_char().
                parent:                 Null_Or( Panemode ),                                    # So we can dynamically inherit keybindings from less specialized panemodes.
                #
                self_insert_command:    Keymap_Node,                                            # Support for C-q handling in   src/lib/x-kit/widget/edit/textpane.pkg
                #
                initialize_panemode_state                                                       # Initialize state for (e.g.) the millgraph-mode part of a textpane at startup. This lets each running Panemode instance maintain private state.  We need multiple states because our parent mode(s) may also be maintaining private state(s).
                  :                                                                             # Our canonical call is from textpane::startup_fn().            # textpane      is from   src/lib/x-kit/widget/edit/textpane.pkg
                  ( Panemode,
                    Panemode_State,
                    Null_Or(Textmill_Extension),
                    List( Panemode_Initialization_Option )
                  )
                  ->
                  ( Panemode_State,
                    Null_Or( Textmill_Extension ),
                    List( Panemode_Initialization_Option )
                  ),

                finalize_state:         (    Panemode, Panemode_State) -> Void,                 # Called when a panemode instance shuts down.
                                                                                                # If you add another drawpane_*_fn here, update the 'want_drawpane' logic in src/lib/x-kit/widget/edit/make-textpane.pkg
                drawpane_startup_fn:            Null_Or( Drawpane_Startup_In            -> Editfn_Out ),
                drawpane_shutdown_fn:           Null_Or( Drawpane_Shutdown_In           -> Editfn_Out ),
                drawpane_initialize_gadget_fn:  Null_Or( Drawpane_Initialize_Gadget_In  -> Editfn_Out ),
                drawpane_redraw_request_fn:     Null_Or( Drawpane_Redraw_Request_In     -> Editfn_Out ),
                drawpane_mouse_click_fn:        Null_Or( Drawpane_Mouse_Click_In        -> Editfn_Out ),
                drawpane_mouse_drag_fn:         Null_Or( Drawpane_Mouse_Drag_In         -> Editfn_Out ),
                drawpane_mouse_transit_fn:      Null_Or( Drawpane_Mouse_Transit_In      -> Editfn_Out )
              }

        also
        Millgraph_Node                                                                          # Information attachable to a node in a Millgraph.
          = MILL_INFO   Mill_Info
          | MILLIN      Millin
          | MILLOUT     Millout

        withtype
        Make_Pane_Guiplan_Fn
          =
          { textpane_to_textmill:       Textpane_To_Textmill,                                   # 
            filepath:                   Null_Or( String ),                                      # make_pane_guiplan will (should!) often select the pane mode to use based on the filename.
            textpane_hint:              Crypt                                                   # Current pane mode (e.g. fundamental_mode) etc, wrapped up so textmill can't see the relevant types, in the interest of modularity.
          }
          ->
          gt::Gp_Widget_Type

        also
        Keymap
          = 
          sm::Map( Keymap_Node )

        also
        Millboss_To_Mill
          =                                                                                     # 
          { id:                         Id,                                                     # Unique id to facilitate storing millboss_to_mill instances in indexed datastructures like red-black trees.
            #
            wakeup:                     {                                                       # These calls are set up by calling mill_to_millboss.wake_me[].
                                          wakeup_arg:           Wakeup_Arg,                                     # 
                                          wakeup_fn:            Wakeup_Arg -> Void              # Mill thunk registered via mill_to_millboss.wake_me[].
                                        }
                                        ->
                                        Void
          }

        also
        Mill_Info                                                                               # Used in millboss_imp when tracking all running mills in textmills_by_name, textmills_by_id, textmills_by_filepath.
          =                                                                                     # I'm keeping this record pure (no Ref cells) so that millboss_imp can safely return Map(Mill_Info) values to clients without risking having their states changed by clients behind millboss_imp's back.
          { mill_id:                    Id,
            freshness:                  Int,                                                    # The larger this number, the more recently the mill was displayed in a pane.  Used to decide which mill to display by default in switch_to_mill -- we default to the freshest mill not currently visible.
            #
            app_to_mill:                App_To_Mill,                                            # Generic interface supported by all mills.
            pane_to_mill:               Crypt,                                                  # Mill-specific interface, typically textpane_to_textmill wrapped by textmill_crypts::encrypt__textpane_to_textmill().
            #
            name:                       String,
            filepath:                   Null_Or( String ),                                      # NULL if the mill has only in-ram state, nothing on disk.
            #
            millins:                    ipm::Map(Millin),                                       # Input  ports exported by this mill.
            millouts:                   opm::Map(Millout),                                      # Output ports exported by this mill.
            #
            millboss_to_mill:           Millboss_To_Mill
          }

        also
        Millgraph                                                                               # Millboss streams these for plugboard or anyone else interested in tracking the global mill interconnect graph.
          =     
          { mills_by_id:                idm::Map( Mill_Info ),                                  # This is the set of all known running mills, indexed by id.  Might as well include these two also, so long as millboss is maintaining them. Silly to force clients to reinvent them:
            mills_by_name:               sm::Map( Mill_Info ),                                  # Same, by name.  
            mills_by_filepath:           sm::Map( Mill_Info ),                                  # Same, by file on which it is open (if any).
            #
            digraph:                    dxy::Graph( Millgraph_Node, Void ),                     # A digraph showing which mill inports are watching which mill outports.  The general graph structure is  mill_node -> outport_node -> inport_node -> mill_node with the arrows being respectively one-to-many, many-to-many, many-to-one.
            #                                                                                   # We map digraphxy::Node(Id)      -> Id        via digraphxy::node_id.
            #                                                                                   # We map digraphxy::Tag(Portpair) -> Portpair  via digraphxy::tag_other.
            #
            mill_nodes:                 idm::Map(dxy::Node(Millgraph_Node)),                    # Maps Id        values to digraph::Node values to map mill       values into digraph land.     This map contains one Mill_Info value for each running mill.
            inport_nodes:               ipm::Map(dxy::Node(Millgraph_Node)),                    # Maps Inport    values to digraph::Node values to map inport     values into digraph land.     This map contains one Millin    value for each input  port on (any) running mill.
            outport_nodes:              opm::Map(dxy::Node(Millgraph_Node)),                    # Maps Outport   values to digraph::Node values to map outport    values into digraph land.     This map contains one Millout   value for each output port on (any) running mill.
            #
            edge_tags:                   sm::Map(dxy::Tag(Void))                                # Maps port_type values to digraph::Tag  values to map watcher/ee values into digraph land.     This map contains one Tag for each port_type string in a Millin or Millout (i.e., each type of datastream in the millgraph).
          }

        also
        Panemode_State                                                                          # We use this to hold the state(s) of a running Panemode instance.
          =                                                                                     # 
          { mode:                       Panemode,                                               # 
            data:                       sm::Map( Crypt )                                        # State information for 'mode' plus all of its ancestors, encoded so they don't need to know each other's types, in the interests of modularity. Map contains one entry each for the mode and its ancestors, indexed by name.
          }

        also
        Textmill_Arg
          =
          { name:                       String,
            textmill_options:           List( Textmill_Option )
          }

        also
        Textmill_State                                                                                                                          # 
          =
          { state:              Ref( Textstate                  ),                                                                              # Current visible state of textmill.
            edit_history:       Ref( Edit_History               ),                                                                              # Recent visible states of textmill, to support undo functionality.
            filepath:           Ref( Null_Or( String )          ),                                                                              # Name of file being edited in buffer, or NULL if no file is associated with buffer contents.
            name:               Ref( String                     ),                                                                              # Name of textmill for display purposes, typically defaults to filename.
            dirty:              Ref( Bool                       ),                                                                              # TRUE if buffer contents have been changed since being read from disk.
            readonly:           Ref( Bool                       ),                                                                              # TRUE if buffer contents are currently marked as read-only.
            textpane_hint:      Ref( Crypt                      )                                                                               # Point+mark etc info stored for textpane.pkg, in a format (only) textpane can decipher.
          }

        also
        Textmill_Imports
          =
          {                                                                                                                                     # Ports we use, provided by other imps.
          }

        also
        Textmill_Statechange__Watchers                                                                                                          # Type for tracking the set of clients subscribed to a mill for Textmill_Statechange updates.
            =                                                                                                                                   #
            ipm::Map( (Inport, (Outport, Textmill_Statechange) -> Void) )                                                                       # 

        also
        Textmill_Statechange_Millout
          =     
          { note_watcher:  ( Inport,
                             Null_Or(Millin),                                                                                                   # Second arg will be NULL if watcher is not another mill (e.g. a pane).
                             (Outport,Textmill_Statechange) -> Void
                           )
                           -> Void,

            drop_watcher:  Inport -> Void                                                                                                       # The Inport must match that given to note_watcher.
          }                              

        also
        Textmill_Statechange__Watchee                                                                                                           # Type for tracking the client we are subscribed to for Textmill_Statechange updates.
          =                                                                                                                                     #
          { wrapped_millout:                    Millout,                                                                                        # 
            millout:                            Textmill_Statechange_Millout                                                                    # Unwrapped version of previous.
          }

        also
        Textmill_Runstate
          =                                                                                                                                     # These values will be statically globally visible throughout the code body for the imp.
          { id:                                 Id,
            me:                                 Textmill_State,                                                                                 # 
            textmill_arg:                       Textmill_Arg,
            textpane_to_textmill:               Textpane_To_Textmill,
            mill_to_millboss:                   Mill_To_Millboss,
            millins:                            ipm::Map(Millin),                                                                               # Millins for this mill indexed by Inport.
            millouts:                           opm::Map(Millout),                                                                              # Output streams available to watch.  Indexed by Outport.
            make_pane_guiplan':                 Make_Pane_Guiplan_Fn,
            finalize_textmill_extension:        Void -> Void,                                                                                   # Function to be called at textmill shutdown, so textmill extension can do any required shutdown of its own.
            imports:                            Textmill_Imports,                                                                               # Imps to which we send requests.
            to:                                 Replyqueue,                                                                                     # The name makes   foo::pass_something(imp) to {. ... }   syntax read well.
            #                                                                                                                                   #
            textmill_statechange__outport:      Outport,                                                                                        # Name of     port on which we stream out textmill changes.
            textmill_statechange__millout:      Millout,                                                                                        #             Port on which we stream out textmill changes.
            textmill_statechange__watchers:     Ref( Textmill_Statechange__Watchers ),                                                          # Watchers of port on which we stream out textmill changes.
            #                                                                                                                                   #
            textmill_statechange__inport:       Inport,                                                                                         # Name of     port on which we read in    textmill changes.
            textmill_statechange__millin:       Millin,                                                                                         #             Port on which we read in    textmill changes.
            textmill_statechange__watchee:      Ref( Null_Or( Textmill_Statechange__Watchee ) ),                                                # Port from           which we read in    textmill changes.
            #                                                                                                                                   #
            end_gun':                           End_Gun                                                                                         # We shut down the microthread when this fires.
          }

        also
        Textmill_Q
          =
          Mailqueue( Textmill_Runstate -> Void )

        also
        Textmill_Extension
          =
          { id                          : Id,                                                   # Unique id for extension, to facilitate distinguishing them and storing them in indexed collections like id_maps.
            #
            initialize_textmill_extension
              :
              { mill_id:                Id,
                textmill_q:             Textmill_Q,
                millins:                ipm::Map(Millin),                                       # Inports  exported by parent textmill.
                millouts:               opm::Map(Millout),                                      # Outports exported by parent textmill.
                make_pane_guiplan':     Make_Pane_Guiplan_Fn
              }
             ->
              {
                millins:                ipm::Map(Millin),                                       # Above 'millins'  augmented as required by this textmill extension.  Parent textmill will publish via its App_To_Mill interface.
                millouts:               opm::Map(Millout),                                      # Above 'millouts' augmented as required by this textmill extension.  Parent textmill will publish via its App_To_Mill interface.
                #
                mill_extension_state:   Crypt,                                                  # Arbitrary private state for this mill extension.
                #
                make_pane_guiplan':             Make_Pane_Guiplan_Fn,
                finalize_textmill_extension:    Void -> Void                                    # Function to be called at textmill shutdown, so textmill extension can do any required shutdown of its own.
              }
          }

        also
        Editfn_In                                                                               # This is what  do_pass_edit_result()  passes to editfns in   src/lib/x-kit/widget/edit/textmill.pkg
          =
          { args:                       List( Prompted_Arg ),
            textlines:                  Textlines,
            point:                      g2d::Point,                                             # As in Point_And_Mark.  (Emacs nomenclature -- 'point' is the visible cursor, 'mark' if set is the other end of the selected region.)
            mark:                       Null_Or( g2d::Point ),                                  # 
            lastmark:                   Null_Or( g2d::Point ),                                  # Last valid value of 'mark' if any -- used to retrieve old mark values by   exchange_point_and_mark    in   src/lib/x-kit/widget/edit/fundamental-mode.pkg
            screen_origin:              g2d::Point,                                             # Origin of pane-visible text relative to textmill contents:  (0,0) means we're showing top of buffer at top of textpane.
            visible_lines:              Int,                                                    # Number of lines of text visible in pane.
            keystring:                  String,                                                 # User keystroke that invoked this editfn.
            readonly:                   Bool,                                                   # TRUE iff textmill contents are currently marked as read-only.
            numeric_prefix:             Null_Or( Int ),                                         # ^U "Universal numeric prefix" value for this editfn if supplied by user, else NULL.
            pane_tag:                   Int,                                                    # Tag of pane for which this editfn is being invoked.  This is a small int for human/GUI use.
            pane_id:                    Id,                                                     # Id  of pane for which this editfn is being invoked.
            mill_id:                    Id,                                                     # Id  of mill for which this editfn is being invoked.
            to:                         Replyqueue,                                             # The name makes   foo::pass_something(imp) to {. ... }   syntax read well.
            edit_history:               Edit_History,                                           # Recent visible states of textmill, to support undo functionality.
            widget_to_guiboss:          gt::Widget_To_Guiboss,                                  # 
            mill_to_millboss:           Mill_To_Millboss,
            #
            mainmill_modestate:         Panemode_State,                                         # Any persistent per-mode state (e.g., private state for fundamental-mode.pkg) for main mill is available via this.
            minimill_modestate:         Panemode_State,                                         # Any persistent per-mode state (e.g., private state for    minimill-mode.pkg) for mini mill is available via this.
            #
            mill_extension_state:       Crypt,
            textpane_to_textmill:       Textpane_To_Textmill,                                   # NB: Editfns run in textmill's microthread to guarantee atomicity, so any attempt by them to invoke blocking textpane_to_textmill.* fns is likely to deadlock.
            mode_to_drawpane:           Null_Or( m2d::Mode_To_Drawpane ),                       # 
            valid_completions:          Null_Or( String -> List(String) )                       # If this is non-NULL then user is entering a commandname or filename or millname(=buffername) on the modeline, and given fn returns all valid completions of string-entered-so-far.
          }

        also
        Editfn_Out                                                                              # Return   NULL    to abort. This is appropriate when operation cannot be performed, for example previous_char called at start of buffer.
          =                                                                                     # Return   THE []  otherwise, where list contains CHANGES to state.  E.g., do not return TEXTLINES unless textlines value was changed.
          Fail_Or (List( Editfn_Out_Option ) )                                                  # One advantage of this system is that additional returns can be accomodated without breaking old code.

        also
        Editfn = Editfn_In -> Editfn_Out

        also
        Plain_Editfn
          =
          { name:                       String,
            doc:                        String,
            args:                       List(Promptfor),                                        # Technically 'parameters', but 'args' is shorter. :-)  Args to read in interactively from user, e.g. filenames and search strings.
            editfn:                     Editfn                                                  # 
          }

        also
        Edit_Arg                                                                                # textpane.pkg passes this to   textmill::pass_edit_result().
          =
          { keystring:                  String,                                                 # User keystroke that invoked this editfn.
            numeric_prefix:             Null_Or( Int ),                                         # ^U "Universal numeric prefix" value for this editfn if supplied by user, else NULL.
            prompted_args:              List( Prompted_Arg ),                                   # Args read interactively from user.
            point_and_mark:             Point_And_Mark,
            lastmark:                   Null_Or(g2d::Point),
            screen_origin:              g2d::Point,                                             # Origin of pane-visible text relative to textmill contents:  (0,0) means we're showing top of buffer at top of textpane.
            visible_lines:              Int,                                                    # Number of lines of text visible in pane.
            log_undo_info:              Bool,                                                   # If log_undo_info is FALSE no entry will be made in the undo history.
            #
            pane_tag:                   Int,                                                    # Tag of pane for which this editfn is being invoked.  This is a small int for human/GUI use.
            pane_id:                    Id,                                                     # Id  of pane for which this editfn is being invoked.
            editfn_node:                Editfn_Node,
            widget_to_guiboss:          gt::Widget_To_Guiboss,                                  # Mainly for access to get_cutbuffer_contents/set_cutbuffer_contents in mill_to_millboss.
            #
            mainmill_modestate:         Panemode_State,
            minimill_modestate:         Panemode_State,
            #
            textpane_to_textmill:       Textpane_To_Textmill,                                   # 
            mode_to_drawpane:           Null_Or( m2d::Mode_To_Drawpane ),                       #
            
            valid_completions:          Null_Or( String -> List(String) )                       # If this is non-NULL then user is entering a commandname or filename or millname(=buffername) on the modeline, and given fn returns all valid completions of string-entered-so-far.
          }

        also
        Drawpane_Startup_Arg                                                                    # This is passed from textpane.pkg to textmill.pkg.
          =
          {
            drawpane_id:                Id,                                                     # Unique id of this drawpane widget.
            doc:                        String,                                                 # Text description of this drawpane widget for debug/display purposes.
            widget_to_guiboss:          gt::Widget_To_Guiboss,                                  # 
            point_and_mark:             Point_And_Mark,
            lastmark:                   Null_Or( g2d::Point ),                                  # Last valid value of 'mark' if any -- used to retrieve old mark values by   exchange_point_and_mark    in   src/lib/x-kit/widget/edit/fundamental-mode.pkg
            screen_origin:              g2d::Point,                                             # Origin of pane-visible text relative to textmill contents:  (0,0) means we're showing top of buffer at top of textpane.
            visible_lines:              Int,                                                    # Number of lines of text visible in pane.
            log_undo_info:              Bool,                                                   # If log_undo_info is FALSE no entry will be made in the undo history.
            pane_tag:                   Int,                                                    # Tag of pane for which this editfn is being invoked.  This is a small int for human/GUI use.
            pane_id:                    Id,                                                     # Id  of pane for which this editfn is being invoked.
            #
            mainmill_modestate:         Panemode_State,                                         # Any persistent per-mode state (e.g., private state for fundamental-mode.pkg) for main mill is available via this.
            minimill_modestate:         Panemode_State,                                         # Any persistent per-mode state (e.g., private state for    minimill-mode.pkg) for mini mill is available via this.
            #
            textpane_to_textmill:       Textpane_To_Textmill,                                   # NB: Editfns run in textmill's microthread to guarantee atomicity, so any attempt by them to invoke blocking textpane_to_textmill.* fns is likely to deadlock.
            mode_to_drawpane:           m2d::Mode_To_Drawpane,
            valid_completions:          Null_Or( String -> List(String) ),                      # If this is non-NULL then user is entering a commandname or filename or millname(=buffername) on the modeline, and given fn returns all valid completions of string-entered-so-far.
            #
            do:                         (Void -> Void) -> Void,                                 # Used by widget subthreads to run code in main widget microthread.
            to:                         Replyqueue                                              # Used to call 'pass_*' methods in other imps.
          }
        also
        Drawpane_Startup_In                                                                     # This is passed from textmill.pkg to foo-mode.pkg
          =
          {
            drawpane_id:                Id,                                                     # Unique id of this drawpane widget.
            doc:                        String,                                                 # Text description of this drawpane widget for debug/display purposes.
            widget_to_guiboss:          gt::Widget_To_Guiboss,                                  # 
            textlines:                  Textlines,
            point_and_mark:             Point_And_Mark,
            lastmark:                   Null_Or( g2d::Point ),                                  # Last valid value of 'mark' if any -- used to retrieve old mark values by   exchange_point_and_mark    in   src/lib/x-kit/widget/edit/fundamental-mode.pkg
            screen_origin:              g2d::Point,                                             # Origin of pane-visible text relative to textmill contents:  (0,0) means we're showing top of buffer at top of textpane.
            visible_lines:              Int,                                                    # Number of lines of text visible in pane.
            readonly:                   Bool,                                                   # TRUE iff textmill contents are currently marked as read-only.
            pane_tag:                   Int,                                                    # Tag of pane for which this editfn is being invoked.  This is a small int for human/GUI use.
            pane_id:                    Id,                                                     # Id  of pane for which this editfn is being invoked.
            mill_id:                    Id,                                                     # Id  of mill for which this editfn is being invoked.
            edit_history:               Edit_History,                                           # Recent visible states of textmill, to support undo functionality.
            mill_to_millboss:           Mill_To_Millboss,
            #
            mainmill_modestate:         Panemode_State,                                         # Any persistent per-mode state (e.g., private state for fundamental-mode.pkg) for main mill is available via this.
            minimill_modestate:         Panemode_State,                                         # Any persistent per-mode state (e.g., private state for    minimill-mode.pkg) for mini mill is available via this.
            #
            mill_extension_state:       Crypt,
            textpane_to_textmill:       Textpane_To_Textmill,                                   # NB: Editfns run in textmill's microthread to guarantee atomicity, so any attempt by them to invoke blocking textpane_to_textmill.* fns is likely to deadlock.
            mode_to_drawpane:           m2d::Mode_To_Drawpane,
            valid_completions:          Null_Or( String -> List(String) ),                      # If this is non-NULL then user is entering a commandname or filename or millname(=buffername) on the modeline, and given fn returns all valid completions of string-entered-so-far.
            #
            do:                         (Void -> Void) -> Void,                                 # Used by widget subthreads to run code in main widget microthread.
            to:                         Replyqueue                                              # Used to call 'pass_*' methods in other imps.
          }

        also
        Drawpane_Shutdown_Arg                                                                   # This is passed from textpane.pkg to textmill.pkg.
          =
          {
            point_and_mark:             Point_And_Mark,
            lastmark:                   Null_Or( g2d::Point ),                                  # Last valid value of 'mark' if any -- used to retrieve old mark values by   exchange_point_and_mark    in   src/lib/x-kit/widget/edit/fundamental-mode.pkg
            screen_origin:              g2d::Point,                                             # Origin of pane-visible text relative to textmill contents:  (0,0) means we're showing top of buffer at top of textpane.
            visible_lines:              Int,                                                    # Number of lines of text visible in pane.
            log_undo_info:              Bool,                                                   # If log_undo_info is FALSE no entry will be made in the undo history.
            pane_tag:                   Int,                                                    # Tag of pane for which this editfn is being invoked.  This is a small int for human/GUI use.
            pane_id:                    Id,                                                     # Id  of pane for which this editfn is being invoked.
            #
            mainmill_modestate:         Panemode_State,                                         # Any persistent per-mode state (e.g., private state for fundamental-mode.pkg) for main mill is available via this.
            minimill_modestate:         Panemode_State,                                         # Any persistent per-mode state (e.g., private state for    minimill-mode.pkg) for mini mill is available via this.
            #
            textpane_to_textmill:       Textpane_To_Textmill,                                   # NB: Editfns run in textmill's microthread to guarantee atomicity, so any attempt by them to invoke blocking textpane_to_textmill.* fns is likely to deadlock.
            mode_to_drawpane:           m2d::Mode_To_Drawpane,
            valid_completions:          Null_Or( String -> List(String) )                       # If this is non-NULL then user is entering a commandname or filename or millname(=buffername) on the modeline, and given fn returns all valid completions of string-entered-so-far.
          }
        also
        Drawpane_Shutdown_In                                                                    # This is passed from textmill.pkg to foo-mode.pkg
          =
          {
            textlines:                  Textlines,
            point_and_mark:             Point_And_Mark,
            lastmark:                   Null_Or( g2d::Point ),                                  # Last valid value of 'mark' if any -- used to retrieve old mark values by   exchange_point_and_mark    in   src/lib/x-kit/widget/edit/fundamental-mode.pkg
            screen_origin:              g2d::Point,                                             # Origin of pane-visible text relative to textmill contents:  (0,0) means we're showing top of buffer at top of textpane.
            visible_lines:              Int,                                                    # Number of lines of text visible in pane.
            readonly:                   Bool,                                                   # TRUE iff textmill contents are currently marked as read-only.
            pane_tag:                   Int,                                                    # Tag of pane for which this editfn is being invoked.  This is a small int for human/GUI use.
            pane_id:                    Id,                                                     # Id  of pane for which this editfn is being invoked.
            mill_id:                    Id,                                                     # Id  of mill for which this editfn is being invoked.
            edit_history:               Edit_History,                                           # Recent visible states of textmill, to support undo functionality.
            mill_to_millboss:           Mill_To_Millboss,
            #
            mainmill_modestate:         Panemode_State,                                         # Any persistent per-mode state (e.g., private state for fundamental-mode.pkg) for main mill is available via this.
            minimill_modestate:         Panemode_State,                                         # Any persistent per-mode state (e.g., private state for    minimill-mode.pkg) for mini mill is available via this.
            #
            mill_extension_state:       Crypt,
            textpane_to_textmill:       Textpane_To_Textmill,                                   # NB: Editfns run in textmill's microthread to guarantee atomicity, so any attempt by them to invoke blocking textpane_to_textmill.* fns is likely to deadlock.
            mode_to_drawpane:           m2d::Mode_To_Drawpane,
            valid_completions:          Null_Or( String -> List(String) )                       # If this is non-NULL then user is entering a commandname or filename or millname(=buffername) on the modeline, and given fn returns all valid completions of string-entered-so-far.
          }

        also
        Drawpane_Initialize_Gadget_Arg                                                          # This is passed from textpane.pkg to textmill.pkg.
          =
          {
            drawpane_id:                Id,                                                     # Unique id of this drawpane widget.
            doc:                        String,                                                 # Text description of this drawpane widget for debug/display purposes.
            site:                       g2d::Box,                                               # Widget's assigned area in window coordinates.
            pass_font:                  List(String) -> Replyqueue
                                                     -> (evt::Font -> Void) -> Void,            # Nonblocking version of next, for use in imps.
             get_font:                  List(String) ->  evt::Font,                             # Accepts a list of font names which are tried in order.
            make_rw_pixmap:             g2d::Size -> g2p::Gadget_To_Rw_Pixmap,                  # Make an Xserver-side rw_pixmap for scratch use by widget.  In general there is no need for the widget to explicitly free these -- guiboss_imp will do this automatically when the gui is killed.
            #
            point_and_mark:             Point_And_Mark,
            lastmark:                   Null_Or( g2d::Point ),                                  # Last valid value of 'mark' if any -- used to retrieve old mark values by   exchange_point_and_mark    in   src/lib/x-kit/widget/edit/fundamental-mode.pkg
            screen_origin:              g2d::Point,                                             # Origin of pane-visible text relative to textmill contents:  (0,0) means we're showing top of buffer at top of textpane.
            visible_lines:              Int,                                                    # Number of lines of text visible in pane.
            log_undo_info:              Bool,                                                   # If log_undo_info is FALSE no entry will be made in the undo history.
            pane_tag:                   Int,                                                    # Tag of pane for which this editfn is being invoked.  This is a small int for human/GUI use.
            pane_id:                    Id,                                                     # Id  of pane for which this editfn is being invoked.
            widget_to_guiboss:          gt::Widget_To_Guiboss,                                  # 
            theme:                      wt::Widget_Theme,
            #
            mainmill_modestate:         Panemode_State,                                         # Any persistent per-mode state (e.g., private state for fundamental-mode.pkg) for main mill is available via this.
            minimill_modestate:         Panemode_State,                                         # Any persistent per-mode state (e.g., private state for    minimill-mode.pkg) for mini mill is available via this.
            #
            textpane_to_textmill:       Textpane_To_Textmill,                                   # NB: Editfns run in textmill's microthread to guarantee atomicity, so any attempt by them to invoke blocking textpane_to_textmill.* fns is likely to deadlock.
            mode_to_drawpane:           m2d::Mode_To_Drawpane,
            valid_completions:          Null_Or( String -> List(String) ),                      # If this is non-NULL then user is entering a commandname or filename or millname(=buffername) on the modeline, and given fn returns all valid completions of string-entered-so-far.
            #
            do:                         (Void -> Void) -> Void,                                 # Used by widget subthreads to run code in main widget microthread.
            to:                         Replyqueue                                              # Used to call 'pass_*' methods in other imps.
          }
        also
        Drawpane_Initialize_Gadget_In                                                           # This is passed from textmill.pkg to foo-mode.pkg
          =
          {
            drawpane_id:                Id,                                                     # Unique id of this drawpane widget.
            doc:                        String,                                                 # Text description of this drawpane widget for debug/display purposes.
            site:                       g2d::Box,                                               # Widget's assigned area in window coordinates.
            pass_font:                  List(String) -> Replyqueue
                                                     -> (evt::Font -> Void) -> Void,            # Nonblocking version of next, for use in imps.
             get_font:                  List(String) ->  evt::Font,                             # Accepts a list of font names which are tried in order.
            make_rw_pixmap:             g2d::Size -> g2p::Gadget_To_Rw_Pixmap,                  # Make an Xserver-side rw_pixmap for scratch use by widget.  In general there is no need for the widget to explicitly free these -- guiboss_imp will do this automatically when the gui is killed.
            #
            textlines:                  Textlines,
            point_and_mark:             Point_And_Mark,
            lastmark:                   Null_Or( g2d::Point ),                                  # Last valid value of 'mark' if any -- used to retrieve old mark values by   exchange_point_and_mark    in   src/lib/x-kit/widget/edit/fundamental-mode.pkg
            screen_origin:              g2d::Point,                                             # Origin of pane-visible text relative to textmill contents:  (0,0) means we're showing top of buffer at top of textpane.
            visible_lines:              Int,                                                    # Number of lines of text visible in pane.
            readonly:                   Bool,                                                   # TRUE iff textmill contents are currently marked as read-only.
            pane_tag:                   Int,                                                    # Tag of pane for which this editfn is being invoked.  This is a small int for human/GUI use.
            pane_id:                    Id,                                                     # Id  of pane for which this editfn is being invoked.
            mill_id:                    Id,                                                     # Id  of mill for which this editfn is being invoked.
            edit_history:               Edit_History,                                           # Recent visible states of textmill, to support undo functionality.
            widget_to_guiboss:          gt::Widget_To_Guiboss,                                  # 
            mill_to_millboss:           Mill_To_Millboss,
            theme:                      wt::Widget_Theme,
            #
            mainmill_modestate:         Panemode_State,                                         # Any persistent per-mode state (e.g., private state for fundamental-mode.pkg) for main mill is available via this.
            minimill_modestate:         Panemode_State,                                         # Any persistent per-mode state (e.g., private state for    minimill-mode.pkg) for mini mill is available via this.
            #
            mill_extension_state:       Crypt,
            textpane_to_textmill:       Textpane_To_Textmill,                                   # NB: Editfns run in textmill's microthread to guarantee atomicity, so any attempt by them to invoke blocking textpane_to_textmill.* fns is likely to deadlock.
            mode_to_drawpane:           m2d::Mode_To_Drawpane,
            valid_completions:          Null_Or( String -> List(String) ),                      # If this is non-NULL then user is entering a commandname or filename or millname(=buffername) on the modeline, and given fn returns all valid completions of string-entered-so-far.
            #
            do:                         (Void -> Void) -> Void,                                 # Used by widget subthreads to run code in main widget microthread.
            to:                         Replyqueue                                              # Used to call 'pass_*' methods in other imps.
          }


        also
        Drawpane_Redraw_Request_Arg                                                             # This is passed from textpane.pkg to textmill.pkg.
          =
          {
            drawpane_id:                Id,                                                     # Unique id of this drawpane widget.
            doc:                        String,                                                 # Text description of this drawpane widget for debug/display purposes.
            frame_number:               Int,                                                    # 1,2,3,... Purely for convenience of widget, guiboss-imp makes no use of this.
            site:                       g2d::Box,                                               # Widget's assigned area in window coordinates.
            duration_in_seconds:        Float,                                                  # If state has changed look-imp should call note_changed_gadget_foreground() before this time is up. Also useful for motionblur.
            gadget_mode:                gt::Gadget_Mode,
            popup_nesting_depth:        Int,                                                    # 0 for gadgets on basewindow, 1 for gadgets on popup on basewindow, 2 for gadgets on popup on popup, etc.
            #
            point_and_mark:             Point_And_Mark,
            lastmark:                   Null_Or( g2d::Point ),                                  # Last valid value of 'mark' if any -- used to retrieve old mark values by   exchange_point_and_mark    in   src/lib/x-kit/widget/edit/fundamental-mode.pkg
            screen_origin:              g2d::Point,                                             # Origin of pane-visible text relative to textmill contents:  (0,0) means we're showing top of buffer at top of textpane.
            visible_lines:              Int,                                                    # Number of lines of text visible in pane.
            log_undo_info:              Bool,                                                   # If log_undo_info is FALSE no entry will be made in the undo history.
            pane_tag:                   Int,                                                    # Tag of pane for which this editfn is being invoked.  This is a small int for human/GUI use.
            pane_id:                    Id,                                                     # Id  of pane for which this editfn is being invoked.
            widget_to_guiboss:          gt::Widget_To_Guiboss,                                  # 
            theme:                      wt::Widget_Theme,
            #
            mainmill_modestate:         Panemode_State,                                         # Any persistent per-mode state (e.g., private state for fundamental-mode.pkg) for main mill is available via this.
            minimill_modestate:         Panemode_State,                                         # Any persistent per-mode state (e.g., private state for    minimill-mode.pkg) for mini mill is available via this.
            #
            textpane_to_textmill:       Textpane_To_Textmill,                                   # NB: Editfns run in textmill's microthread to guarantee atomicity, so any attempt by them to invoke blocking textpane_to_textmill.* fns is likely to deadlock.
            mode_to_drawpane:           m2d::Mode_To_Drawpane,                                  # 
            valid_completions:          Null_Or( String -> List(String) ),                      # If this is non-NULL then user is entering a commandname or filename or millname(=buffername) on the modeline, and given fn returns all valid completions of string-entered-so-far.
            #
            do:                         (Void -> Void) -> Void,                                 # Used by widget subthreads to run code in main widget microthread.
            to:                         Replyqueue                                              # Used to call 'pass_*' methods in other imps.
          }
        also
        Drawpane_Redraw_Request_In                                                              # This is passed from textmill.pkg to foo-mode.pkg
          =
          {
            drawpane_id:                Id,                                                     # Unique id of this drawpane widget.
            doc:                        String,                                                 # Text description of this drawpane widget for debug/display purposes.
            frame_number:               Int,                                                    # 1,2,3,... Purely for convenience of widget, guiboss-imp makes no use of this.
            site:                       g2d::Box,                                               # Widget's assigned area in window coordinates.
            duration_in_seconds:        Float,                                                  # If state has changed look-imp should call note_changed_gadget_foreground() before this time is up. Also useful for motionblur.
            gadget_mode:                gt::Gadget_Mode,
            popup_nesting_depth:        Int,                                                    # 0 for gadgets on basewindow, 1 for gadgets on popup on basewindow, 2 for gadgets on popup on popup, etc.
            #
            textlines:                  Textlines,
            point_and_mark:             Point_And_Mark,
            lastmark:                   Null_Or( g2d::Point ),                                  # Last valid value of 'mark' if any -- used to retrieve old mark values by   exchange_point_and_mark    in   src/lib/x-kit/widget/edit/fundamental-mode.pkg
            screen_origin:              g2d::Point,                                             # Origin of pane-visible text relative to textmill contents:  (0,0) means we're showing top of buffer at top of textpane.
            visible_lines:              Int,                                                    # Number of lines of text visible in pane.
            readonly:                   Bool,                                                   # TRUE iff textmill contents are currently marked as read-only.
            pane_tag:                   Int,                                                    # Tag of pane for which this editfn is being invoked.  This is a small int for human/GUI use.
            pane_id:                    Id,                                                     # Id  of pane for which this editfn is being invoked.
            mill_id:                    Id,                                                     # Id  of mill for which this editfn is being invoked.
            edit_history:               Edit_History,                                           # Recent visible states of textmill, to support undo functionality.
            widget_to_guiboss:          gt::Widget_To_Guiboss,                                  # 
            mill_to_millboss:           Mill_To_Millboss,
            theme:                      wt::Widget_Theme,
            #
            mainmill_modestate:         Panemode_State,                                         # Any persistent per-mode state (e.g., private state for fundamental-mode.pkg) for main mill is available via this.
            minimill_modestate:         Panemode_State,                                         # Any persistent per-mode state (e.g., private state for    minimill-mode.pkg) for mini mill is available via this.
            #
            mill_extension_state:       Crypt,
            textpane_to_textmill:       Textpane_To_Textmill,                                   # NB: Editfns run in textmill's microthread to guarantee atomicity, so any attempt by them to invoke blocking textpane_to_textmill.* fns is likely to deadlock.
            mode_to_drawpane:           m2d::Mode_To_Drawpane,                                  # 
            valid_completions:          Null_Or( String -> List(String) ),                      # If this is non-NULL then user is entering a commandname or filename or millname(=buffername) on the modeline, and given fn returns all valid completions of string-entered-so-far.
            #
            do:                         (Void -> Void) -> Void,                                 # Used by widget subthreads to run code in main widget microthread.
            to:                         Replyqueue                                              # Used to call 'pass_*' methods in other imps.
          }

        also
        Drawpane_Mouse_Click_Arg                                                                # This is passed from textpane.pkg to textmill.pkg.
          =
          {
            drawpane_id:                Id,                                                     # Unique id of this drawpane widget.
            doc:                        String,                                                 # Text description of this drawpane widget for debug/display purposes.
            button:                     evt::Mousebutton,
            event:                      gt::Mousebutton_Event,                                  # MOUSEBUTTON_PRESS or MOUSEBUTTON_RELEASE.
            point:                      g2d::Point,
            widget_layout_hint:         gt::Widget_Layout_Hint,
            frame_indent_hint:          gt::Frame_Indent_Hint,
            site:                       g2d::Box,                                               # Widget's assigned area in window coordinates.
            modifier_keys_state:        evt::Modifier_Keys_State,                               # State of the modifier keys (shift, ctrl...).
            mousebuttons_state:         evt::Mousebuttons_State,                                # State of mouse buttons as a bool record.
            point_and_mark:             Point_And_Mark,
            lastmark:                   Null_Or( g2d::Point ),                                  # Last valid value of 'mark' if any -- used to retrieve old mark values by   exchange_point_and_mark    in   src/lib/x-kit/widget/edit/fundamental-mode.pkg
            screen_origin:              g2d::Point,                                             # Origin of pane-visible text relative to textmill contents:  (0,0) means we're showing top of buffer at top of textpane.
            visible_lines:              Int,                                                    # Number of lines of text visible in pane.
            log_undo_info:              Bool,                                                   # If log_undo_info is FALSE no entry will be made in the undo history.
            pane_tag:                   Int,                                                    # Tag of pane for which this editfn is being invoked.  This is a small int for human/GUI use.
            pane_id:                    Id,                                                     # Id  of pane for which this editfn is being invoked.
            widget_to_guiboss:          gt::Widget_To_Guiboss,                                  # 
            theme:                      wt::Widget_Theme,
            #
            mainmill_modestate:         Panemode_State,                                         # Any persistent per-mode state (e.g., private state for fundamental-mode.pkg) for main mill is available via this.
            minimill_modestate:         Panemode_State,                                         # Any persistent per-mode state (e.g., private state for    minimill-mode.pkg) for mini mill is available via this.
            #
            textpane_to_textmill:       Textpane_To_Textmill,                                   # NB: Editfns run in textmill's microthread to guarantee atomicity, so any attempt by them to invoke blocking textpane_to_textmill.* fns is likely to deadlock.
            mode_to_drawpane:           m2d::Mode_To_Drawpane,                                  # 
            valid_completions:          Null_Or( String -> List(String) ),                      # If this is non-NULL then user is entering a commandname or filename or millname(=buffername) on the modeline, and given fn returns all valid completions of string-entered-so-far.
            #
            do:                         (Void -> Void) -> Void,                                 # Used by widget subthreads to run code in main widget microthread.
            to:                         Replyqueue                                              # Used to call 'pass_*' methods in other imps.
          }
        also
        Drawpane_Mouse_Click_In                                                                 # This is passed from textmill.pkg to foo-mode.pkg
          =
          {
            drawpane_id:                Id,                                                     # Unique id of this drawpane widget.
            doc:                        String,                                                 # Text description of this drawpane widget for debug/display purposes.
            button:                     evt::Mousebutton,
            event:                      gt::Mousebutton_Event,                                  # MOUSEBUTTON_PRESS or MOUSEBUTTON_RELEASE.
            point:                      g2d::Point,
            widget_layout_hint:         gt::Widget_Layout_Hint,
            frame_indent_hint:          gt::Frame_Indent_Hint,
            site:                       g2d::Box,                                               # Widget's assigned area in window coordinates.
            modifier_keys_state:        evt::Modifier_Keys_State,                               # State of the modifier keys (shift, ctrl...).
            mousebuttons_state:         evt::Mousebuttons_State,                                # State of mouse buttons as a bool record.
            textlines:                  Textlines,
            point_and_mark:             Point_And_Mark,
            lastmark:                   Null_Or( g2d::Point ),                                  # Last valid value of 'mark' if any -- used to retrieve old mark values by   exchange_point_and_mark    in   src/lib/x-kit/widget/edit/fundamental-mode.pkg
            screen_origin:              g2d::Point,                                             # Origin of pane-visible text relative to textmill contents:  (0,0) means we're showing top of buffer at top of textpane.
            visible_lines:              Int,                                                    # Number of lines of text visible in pane.
            readonly:                   Bool,                                                   # TRUE iff textmill contents are currently marked as read-only.
            pane_tag:                   Int,                                                    # Tag of pane for which this editfn is being invoked.  This is a small int for human/GUI use.
            pane_id:                    Id,                                                     # Id  of pane for which this editfn is being invoked.
            mill_id:                    Id,                                                     # Id  of mill for which this editfn is being invoked.
            edit_history:               Edit_History,                                           # Recent visible states of textmill, to support undo functionality.
            widget_to_guiboss:          gt::Widget_To_Guiboss,                                  # 
            mill_to_millboss:           Mill_To_Millboss,
            theme:                      wt::Widget_Theme,
            #
            mainmill_modestate:         Panemode_State,                                         # Any persistent per-mode state (e.g., private state for fundamental-mode.pkg) for main mill is available via this.
            minimill_modestate:         Panemode_State,                                         # Any persistent per-mode state (e.g., private state for    minimill-mode.pkg) for mini mill is available via this.
            #
            mill_extension_state:       Crypt,
            textpane_to_textmill:       Textpane_To_Textmill,                                   # NB: Editfns run in textmill's microthread to guarantee atomicity, so any attempt by them to invoke blocking textpane_to_textmill.* fns is likely to deadlock.
            mode_to_drawpane:           m2d::Mode_To_Drawpane,                                  # 
            valid_completions:          Null_Or( String -> List(String) ),                      # If this is non-NULL then user is entering a commandname or filename or millname(=buffername) on the modeline, and given fn returns all valid completions of string-entered-so-far.
            #
            do:                         (Void -> Void) -> Void,                                 # Used by widget subthreads to run code in main widget microthread.
            to:                         Replyqueue                                              # Used to call 'pass_*' methods in other imps.
          }

        also
        Drawpane_Mouse_Drag_Arg                                                                 # This is passed from textpane.pkg to textmill.pkg.
          =
          {
            drawpane_id:                Id,                                                     # Unique id of this drawpane widget.
            doc:                        String,                                                 # Text description of this drawpane widget for debug/display purposes.
            button:                     evt::Mousebutton,
            event_point:                g2d::Point,
            start_point:                g2d::Point,
            last_point:                 g2d::Point,
            phase:                      gt::Drag_Phase, 
            widget_layout_hint:         gt::Widget_Layout_Hint,
            frame_indent_hint:          gt::Frame_Indent_Hint,
            site:                       g2d::Box,                                               # Widget's assigned area in window coordinates.
            modifier_keys_state:        evt::Modifier_Keys_State,                               # State of the modifier keys (shift, ctrl...).
            mousebuttons_state:         evt::Mousebuttons_State,                                # State of mouse buttons as a bool record.
            point_and_mark:             Point_And_Mark,
            lastmark:                   Null_Or( g2d::Point ),                                  # Last valid value of 'mark' if any -- used to retrieve old mark values by   exchange_point_and_mark    in   src/lib/x-kit/widget/edit/fundamental-mode.pkg
            screen_origin:              g2d::Point,                                             # Origin of pane-visible text relative to textmill contents:  (0,0) means we're showing top of buffer at top of textpane.
            visible_lines:              Int,                                                    # Number of lines of text visible in pane.
            log_undo_info:              Bool,                                                   # If log_undo_info is FALSE no entry will be made in the undo history.
            pane_tag:                   Int,                                                    # Tag of pane for which this editfn is being invoked.  This is a small int for human/GUI use.
            pane_id:                    Id,                                                     # Id  of pane for which this editfn is being invoked.
            widget_to_guiboss:          gt::Widget_To_Guiboss,                                  # 
            theme:                      wt::Widget_Theme,
            #
            mainmill_modestate:         Panemode_State,                                         # Any persistent per-mode state (e.g., private state for fundamental-mode.pkg) for main mill is available via this.
            minimill_modestate:         Panemode_State,                                         # Any persistent per-mode state (e.g., private state for    minimill-mode.pkg) for mini mill is available via this.
            #
            textpane_to_textmill:       Textpane_To_Textmill,                                   # NB: Editfns run in textmill's microthread to guarantee atomicity, so any attempt by them to invoke blocking textpane_to_textmill.* fns is likely to deadlock.
            mode_to_drawpane:           m2d::Mode_To_Drawpane,                                  # 
            valid_completions:          Null_Or( String -> List(String) ),                      # If this is non-NULL then user is entering a commandname or filename or millname(=buffername) on the modeline, and given fn returns all valid completions of string-entered-so-far.
            #
            do:                         (Void -> Void) -> Void,                                 # Used by widget subthreads to run code in main widget microthread.
            to:                         Replyqueue                                              # Used to call 'pass_*' methods in other imps.
          }
        also
        Drawpane_Mouse_Drag_In                                                                  # This is passed from textmill.pkg to foo-mode.pkg
          =
          {
            drawpane_id:                Id,                                                     # Unique id of this drawpane widget.
            doc:                        String,                                                 # Text description of this drawpane widget for debug/display purposes.
            button:                     evt::Mousebutton,
            event_point:                g2d::Point,
            start_point:                g2d::Point,
            last_point:                 g2d::Point,
            phase:                      gt::Drag_Phase, 
            widget_layout_hint:         gt::Widget_Layout_Hint,
            frame_indent_hint:          gt::Frame_Indent_Hint,
            site:                       g2d::Box,                                               # Widget's assigned area in window coordinates.
            modifier_keys_state:        evt::Modifier_Keys_State,                               # State of the modifier keys (shift, ctrl...).
            mousebuttons_state:         evt::Mousebuttons_State,                                # State of mouse buttons as a bool record.
            textlines:                  Textlines,
            point_and_mark:             Point_And_Mark,
            lastmark:                   Null_Or( g2d::Point ),                                  # Last valid value of 'mark' if any -- used to retrieve old mark values by   exchange_point_and_mark    in   src/lib/x-kit/widget/edit/fundamental-mode.pkg
            screen_origin:              g2d::Point,                                             # Origin of pane-visible text relative to textmill contents:  (0,0) means we're showing top of buffer at top of textpane.
            visible_lines:              Int,                                                    # Number of lines of text visible in pane.
            readonly:                   Bool,                                                   # TRUE iff textmill contents are currently marked as read-only.
            pane_tag:                   Int,                                                    # Tag of pane for which this editfn is being invoked.  This is a small int for human/GUI use.
            pane_id:                    Id,                                                     # Id  of pane for which this editfn is being invoked.
            mill_id:                    Id,                                                     # Id  of mill for which this editfn is being invoked.
            edit_history:               Edit_History,                                           # Recent visible states of textmill, to support undo functionality.
            widget_to_guiboss:          gt::Widget_To_Guiboss,                                  # 
            mill_to_millboss:           Mill_To_Millboss,
            theme:                      wt::Widget_Theme,
            #
            mainmill_modestate:         Panemode_State,                                         # Any persistent per-mode state (e.g., private state for fundamental-mode.pkg) for main mill is available via this.
            minimill_modestate:         Panemode_State,                                         # Any persistent per-mode state (e.g., private state for    minimill-mode.pkg) for mini mill is available via this.
            #
            mill_extension_state:       Crypt,
            textpane_to_textmill:       Textpane_To_Textmill,                                   # NB: Editfns run in textmill's microthread to guarantee atomicity, so any attempt by them to invoke blocking textpane_to_textmill.* fns is likely to deadlock.
            mode_to_drawpane:           m2d::Mode_To_Drawpane,                                  # 
            valid_completions:          Null_Or( String -> List(String) ),                      # If this is non-NULL then user is entering a commandname or filename or millname(=buffername) on the modeline, and given fn returns all valid completions of string-entered-so-far.
            #
            do:                         (Void -> Void) -> Void,                                 # Used by widget subthreads to run code in main widget microthread.
            to:                         Replyqueue                                              # Used to call 'pass_*' methods in other imps.
          }

        also
        Drawpane_Mouse_Transit_Arg                                                              # This is passed from textpane.pkg to textmill.pkg.
          =
          {
            drawpane_id:                Id,                                                     # Unique id of this drawpane widget.
            doc:                        String,                                                 # Text description of this drawpane widget for debug/display purposes.
            transit:                    gt::Gadget_Transit,                                     # Mouse is entering (CAME) or leaving (LEFT) widget, or moving (MOVE) across it.
            event_point:                g2d::Point,
            widget_layout_hint:         gt::Widget_Layout_Hint,
            frame_indent_hint:          gt::Frame_Indent_Hint,
            site:                       g2d::Box,                                               # Widget's assigned area in window coordinates.
            modifier_keys_state:        evt::Modifier_Keys_State,                               # State of the modifier keys (shift, ctrl...).
            point_and_mark:             Point_And_Mark,
            lastmark:                   Null_Or( g2d::Point ),                                  # Last valid value of 'mark' if any -- used to retrieve old mark values by   exchange_point_and_mark    in   src/lib/x-kit/widget/edit/fundamental-mode.pkg
            screen_origin:              g2d::Point,                                             # Origin of pane-visible text relative to textmill contents:  (0,0) means we're showing top of buffer at top of textpane.
            visible_lines:              Int,                                                    # Number of lines of text visible in pane.
            log_undo_info:              Bool,                                                   # If log_undo_info is FALSE no entry will be made in the undo history.
            pane_tag:                   Int,                                                    # Tag of pane for which this editfn is being invoked.  This is a small int for human/GUI use.
            pane_id:                    Id,                                                     # Id  of pane for which this editfn is being invoked.
            widget_to_guiboss:          gt::Widget_To_Guiboss,                                  # 
            theme:                      wt::Widget_Theme,
            #
            mainmill_modestate:         Panemode_State,                                         # Any persistent per-mode state (e.g., private state for fundamental-mode.pkg) for main mill is available via this.
            minimill_modestate:         Panemode_State,                                         # Any persistent per-mode state (e.g., private state for    minimill-mode.pkg) for mini mill is available via this.
            #
            textpane_to_textmill:       Textpane_To_Textmill,                                   # NB: Editfns run in textmill's microthread to guarantee atomicity, so any attempt by them to invoke blocking textpane_to_textmill.* fns is likely to deadlock.
            mode_to_drawpane:           m2d::Mode_To_Drawpane,                                  # 
            valid_completions:          Null_Or( String -> List(String) ),                      # If this is non-NULL then user is entering a commandname or filename or millname(=buffername) on the modeline, and given fn returns all valid completions of string-entered-so-far.
            #
            do:                         (Void -> Void) -> Void,                                 # Used by widget subthreads to run code in main widget microthread.
            to:                         Replyqueue                                              # Used to call 'pass_*' methods in other imps.
          }
        also
        Drawpane_Mouse_Transit_In                                                               # This is passed from textmill.pkg to foo-mode.pkg
          =
          {
            drawpane_id:                Id,                                                     # Unique id of this drawpane widget.
            doc:                        String,                                                 # Text description of this drawpane widget for debug/display purposes.
            transit:                    gt::Gadget_Transit,                                     # Mouse is entering (CAME) or leaving (LEFT) widget, or moving (MOVE) across it.
            event_point:                g2d::Point,
            widget_layout_hint:         gt::Widget_Layout_Hint,
            frame_indent_hint:          gt::Frame_Indent_Hint,
            site:                       g2d::Box,                                               # Widget's assigned area in window coordinates.
            modifier_keys_state:        evt::Modifier_Keys_State,                               # State of the modifier keys (shift, ctrl...).
            textlines:                  Textlines,
            point_and_mark:             Point_And_Mark,
            lastmark:                   Null_Or( g2d::Point ),                                  # Last valid value of 'mark' if any -- used to retrieve old mark values by   exchange_point_and_mark    in   src/lib/x-kit/widget/edit/fundamental-mode.pkg
            screen_origin:              g2d::Point,                                             # Origin of pane-visible text relative to textmill contents:  (0,0) means we're showing top of buffer at top of textpane.
            visible_lines:              Int,                                                    # Number of lines of text visible in pane.
            readonly:                   Bool,                                                   # TRUE iff textmill contents are currently marked as read-only.
            pane_tag:                   Int,                                                    # Tag of pane for which this editfn is being invoked.  This is a small int for human/GUI use.
            pane_id:                    Id,                                                     # Id  of pane for which this editfn is being invoked.
            mill_id:                    Id,                                                     # Id  of mill for which this editfn is being invoked.
            edit_history:               Edit_History,                                           # Recent visible states of textmill, to support undo functionality.
            widget_to_guiboss:          gt::Widget_To_Guiboss,                                  # 
            mill_to_millboss:           Mill_To_Millboss,
            theme:                      wt::Widget_Theme,
            #
            mainmill_modestate:         Panemode_State,                                         # Any persistent per-mode state (e.g., private state for fundamental-mode.pkg) for main mill is available via this.
            minimill_modestate:         Panemode_State,                                         # Any persistent per-mode state (e.g., private state for    minimill-mode.pkg) for mini mill is available via this.
            #
            mill_extension_state:       Crypt,
            textpane_to_textmill:       Textpane_To_Textmill,                                   # NB: Editfns run in textmill's microthread to guarantee atomicity, so any attempt by them to invoke blocking textpane_to_textmill.* fns is likely to deadlock.
            mode_to_drawpane:           m2d::Mode_To_Drawpane,                                  # 
            valid_completions:          Null_Or( String -> List(String) ),                      # If this is non-NULL then user is entering a commandname or filename or millname(=buffername) on the modeline, and given fn returns all valid completions of string-entered-so-far.
            #
            do:                         (Void -> Void) -> Void,                                 # Used by widget subthreads to run code in main widget microthread.
            to:                         Replyqueue                                              # Used to call 'pass_*' methods in other imps.
          };



        Textmill_Spec                                                                           # A textpane is a window onto a textmill, so when creating a textpane we must somehow specify what textmill to display.
          #                                                                                     # This type gets consumed by textpane::with in   src/lib/x-kit/widget/edit/textpane.pkg
          = OLD_TEXTMILL_BY_NAME        String                                                  # Display a pre-existing textmill, fetching it by given name   via et::Mill_To_Millboss.get_textmill.
          | OLD_TEXTMILL_BY_PORT        Textpane_To_Textmill                                    # Display a pre-existing textmill, specified by given port to it.
          | NEW_TEXTMILL                Textmill_Arg                                            # Display a newly made   textmill, created via et::Mill_To_Millboss.make_textmill.
          ;

        exception  MILL_TO_MILLBOSS__CRYPT              Mill_To_Millboss;
        exception  TEXTPANE_TO_SCREENLINE__CRYPT        p2l::Textpane_To_Screenline;
        #
        exception  MODE_AND_TEXTPANE_TO_DRAWPANE__CRYPT ( p2d::Textpane_To_Drawpane, 
                                                          m2d::Mode_To_Drawpane
                                                        );


        mill_to_millboss__global                                                                # millboss_imp will set this non-NULL when it starts up.  This provides an assured way for any mill to contact millboss.
            =                                                                                   # We used to do this via gadget_to_guiboss but mills shouldn't have to know about gui stuff.
            REF (NULL: Null_Or(Mill_To_Millboss));

        fun get__mill_to_millboss  (caller:  String):  Mill_To_Millboss
            =
            case *mill_to_millboss__global
                #
                THE mill_to_millboss =>  mill_to_millboss;

                NULL => {   msg =  sprintf "mill_to_millboss_global not set by millboss_imp in time?! -- millboss_types::get__mill_to_millboss called by %s" caller;
                            log::fatal msg;
                            raise exception DIE msg;
                        };
            esac;


        empty_keymap =  sm::empty: Keymap;                                                      # Helps clients abstract a bit from current specific implementation of keymaps.

        stipulate                                                                               # This idiom borrowed from   src/lib/src/quickstring.pkg
            #
            lock = make_full_maildrop ();
            #
        herein
            fun atomically f a
                =
                {   take_from_maildrop lock;
                    #
                    f a
                    then
                        put_in_maildrop (lock, ());
                };
        end;

        stipulate
            #
            all_known_editfns_by_name
                =
                REF (sm::empty: sm::Map( Editfn_Node ));

            fun note_editfn (keymap_node: Keymap_Node): Void
                =
                case keymap_node
                    #
                    EDITFN editfn
                        =>
                        {   name =  case editfn
                                        #
                                        PLAIN_EDITFN { name, ... }
                                            =>
                                            name;

                                        FANCY_EDITFN
                                            =>
                                            {   msg = "FANCY_EDITFN not yet supported (or defined).";
                                                log::fatal msg;
                                                raise exception DIE msg;
                                            };
                                    esac;

                            all_known_editfns_by_name
                                :=
                                sm::set (*all_known_editfns_by_name, name, editfn);
                        };

                    _ => ();
                esac;

        herein
            note_editfn =  atomically  note_editfn;                                             # Use 'atomically' to avoid barely-conceivable bugs due to concurrent micro/threads trying to simultaneously register editfns.
            
            fun get_all_known_editfns_by_name ()                                                # No obvious reason to use 'atomically' here:  reading a refcell basically is atomic anyhow.
                =
                *all_known_editfns_by_name;
        end;

        fun keystring_to_modemap_key                                                            # Convert keystroke string from guishim-imp-for-x.pkg (or other guishim) into traditional emacs keymap representation like "C-SPC" or "C-M-q" or such.
              (
                keystring:              String,
                modifier_keys_state:    evt::Modifier_Keys_State
              )
            =
            if (keystring == "")
                #
                keystring;                                                                      # Mostly just so we don't have to worry about empty strings in the rest of the routine.

            else
                modifier_keys_state
                  ->
                  { shift_key_was_down:         Bool,
                    shiftlock_key_was_down:     Bool,
                    control_key_was_down:       Bool,
                    mod1_key_was_down:          Bool,                                           # ALT, which emacs traditionally interprets as META modifier key.
                    mod2_key_was_down:          Bool,
                    mod3_key_was_down:          Bool,
                    mod4_key_was_down:          Bool,                                           # Windows/Command key, which emacs traditionally interprets as SUPER modifier key.
                    mod5_key_was_down:          Bool
                  };

                my (keystring, control_key_was_down)                                            # Normalize actual control chars to modkey + alphabetic representation.
                    =
                    case keystring
                        #
                        "\^@"   =>      ("@", TRUE);
                        "\^A"   =>      ("a", TRUE);
                        "\^B"   =>      ("b", TRUE);
                        "\^C"   =>      ("c", TRUE);
                        "\^D"   =>      ("d", TRUE);
                        "\^E"   =>      ("e", TRUE);
                        "\^F"   =>      ("f", TRUE);
                        "\^G"   =>      ("g", TRUE);
                        "\^H"   =>      ("h", TRUE);
                        "\^I"   =>      ("i", TRUE);
                        "\^J"   =>      ("j", TRUE);
                        "\^K"   =>      ("k", TRUE);
                        "\^L"   =>      ("l", TRUE);
                        "\^M"   =>      ("m", TRUE);
                        "\^N"   =>      ("n", TRUE);
                        "\^O"   =>      ("o", TRUE);
                        "\^P"   =>      ("p", TRUE);
                        "\^Q"   =>      ("q", TRUE);
                        "\^R"   =>      ("r", TRUE);
                        "\^S"   =>      ("s", TRUE);
                        "\^T"   =>      ("t", TRUE);
                        "\^U"   =>      ("u", TRUE);
                        "\^V"   =>      ("v", TRUE);
                        "\^W"   =>      ("w", TRUE);
                        "\^X"   =>      ("x", TRUE);
                        "\^Y"   =>      ("y", TRUE);
                        "\^Z"   =>      ("z", TRUE);
                        "\^["   =>      ("[", TRUE);
                        "\^\"   =>      ("\\",TRUE);
                        "\^]"   =>      ("]", TRUE);
                        "\^_"   =>      ("_", TRUE);
                        #
                        _       =>      (keystring, control_key_was_down);
                    esac;

                my (keystring, control_key_was_down)                                            # A few ad hoc traditional names.
                    =
                    case (keystring, control_key_was_down)
                        #
                        ("i", TRUE) => ("TAB", FALSE);
                        ("m", TRUE) => ("RET", FALSE);
                        ("[", TRUE) => ("ESC", FALSE);
                        #
                        _           => (keystring, control_key_was_down);
                    esac;

                keystring = if (keystring == " ")   "SPC";
                            else                    keystring;
                            fi;

                # By inspection of describe-bindings output,
                # the canonical emacs ordering for the
                #
                #     Super = 's-'
                #     Meta  = 'M-'
                #     Ctrl  = 'C-'
                #     Shift = 'S-'
                #
                # prefixes seems to be
                #
                #     s-C-M-S-x
                #
                # Here we build them up in right-to-left order:

                keystring                                                       # The shift modifier 'S-' is only useful on special keys, which are represented in angle brackets, eg "<backspace>" or "<home>".
                    =
                    {   bytelen = string::length_in_bytes   keystring;
                        charlen = string::length_in_chars   keystring;
                        #
                        if (charlen < 3)
                            #
                            keystring;
                        else
                            firstchar =  string::get_byte_as_char (keystring, 0);
                            lastchar  =  string::get_byte_as_char (keystring, bytelen - 1);

                            keystring
                                =
                                case ( firstchar,
                                       lastchar,
                                       shift_key_was_down or shiftlock_key_was_down
                                     )
                                    #
                                    ('<', '>', TRUE) => "S-" + keystring;       # We *do* have something like "<backspace>" and shift *is* set, so add the S- prefix.
                                    _                =>        keystring;       # Ignore shift (if any) because in cases like 4 vs $ (etc) it is implicit in the keystring.
                                esac;

                            keystring;
                        fi;
                    };

                keystring                                                       # The META modifier 'M-' may be applied to anything.
                    =
                    case mod1_key_was_down
                        #
                        TRUE        => "M-" + keystring;
                        _           =>        keystring;
                    esac;

                keystring                                                       # The CTRL modifier 'C-' may be applied to anything.
                    =
                    case control_key_was_down
                        #
                        TRUE        => "C-" + keystring;
                        _           =>        keystring;
                    esac;

                keystring                                                       # The SUPER modifier 's-' may be applied to anything.
                    =
                    case mod4_key_was_down
                        #
                        TRUE        => "s-" + keystring;
                        _           =>        keystring;
                    esac;


                keystring;
            fi;



        fun add_editfn_to_keymap
              (
                keymap:         Keymap,
                key:            List(String),                                                   # The strings should have been run through keystring_to_modemap_key() or be in its format.  List has one string for single-keystroke commands, two strings for single-prefix commands etc.
                keymap_node:    Keymap_Node
              )
            :                   Keymap
            =
            case key
                #
                []       => keymap;                                                             # Shouldn't happen.

                k ! []   => sm::set (keymap, k, keymap_node);

                k ! rest => {   subkeymap = case (sm::get (keymap, k))
                                                #
                                                THE (SUBKEYMAP subkeymap)
                                                    =>
                                                    subkeymap;                                  # Use existing subkeymap for this prefix key.

                                                _   =>  empty_keymap;                           # Start a new subkeymap for this prefix key.
                                            esac;

                                subkeymap
                                    =
                                    add_editfn_to_keymap (subkeymap, rest, keymap_node);

                                sm::set (keymap, k, SUBKEYMAP subkeymap);                       # Silently clobber any previous non-prefix-key keymap_node associated with 'k'.
                            };
            esac;


        fun add_editfn_to_keymap_throughout_char_range                                          # Emacs directly represents char ranges in keymaps, but for now we'll keep our keymaps simple.  Ram is a million times cheaper now than it was in the early 1970s when emacs was designed. :-)
              {
                keymap:         Keymap,
                keymap_node:    Keymap_Node,
                #
                firstchar:      Char,
                lastchar:       Char
              }
            :                   Keymap
            =
            {   keymap =    loop (firstchar, keymap)
                            where
                                fun loop (c: Char, keymap: Keymap)
                                    =
                                    if (c > lastchar)
                                        #
                                        keymap;
                                    else
                                        key = char::to_string c;

                                        key =   case key                                        # This is a little bugfix; we were unable to insert  "  or  \  into an editbuffer because the keymap had the chars backslashed (two-byte strings) and the incoming keystrings had them non-backslashed (one-byte) strings.
                                                    #                                           # The difference arose in to_string() in   src/lib/std/src/char.pkg
                                                    "\\\"" => "\"";                             # I'm reluctant to change that fn because a lot of existing code might break, so instead I'm
                                                    "\\\\" => "\\";                             # doing this ugly little patch here to paper over the problem Captain-Crunch style.  --2015-09-15 CrT
                                                    _      =>  key;
                                                esac;

                                        key = keystring_to_modemap_key (key, evt::no_modifier_keys_were_down);
                                        #
                                        keymap = sm::set (keymap, key, keymap_node);

                                        loop (char::next c,  keymap);
                                    fi;
                            end;
                
                keymap;
            };  
    };

end;





Comments and suggestions to: bugs@mythryl.org

PreviousUpNext