PreviousUpNext

15.4.1418  src/lib/x-kit/widget/edit/minimill-mode.pkg

## minimill-mode.pkg
#
# Mode for interactive string entry via the modeline screen area.
#
# 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/edit/eval-mode.pkg
#     src/lib/x-kit/widget/edit/fundamental-mode.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 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 gt  =  guiboss_types;                               # guiboss_types                 is from   src/lib/x-kit/widget/gui/guiboss-types.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 ct  =  cutbuffer_types;                             # cutbuffer_types               is from   src/lib/x-kit/widget/edit/cutbuffer-types.pkg
#   package ct  =  gui_to_object_theme;                         # gui_to_object_theme           is from   src/lib/x-kit/widget/theme/object/gui-to-object-theme.pkg
#   package bt  =  gui_to_sprite_theme;                         # gui_to_sprite_theme           is from   src/lib/x-kit/widget/theme/sprite/gui-to-sprite-theme.pkg
#   package wt  =  widget_theme;                                # widget_theme                  is from   src/lib/x-kit/widget/theme/widget/widget-theme.pkg


    package boi =  spritespace_imp;                             # spritespace_imp               is from   src/lib/x-kit/widget/space/sprite/spritespace-imp.pkg
    package cai =  objectspace_imp;                             # objectspace_imp               is from   src/lib/x-kit/widget/space/object/objectspace-imp.pkg
    package pai =  widgetspace_imp;                             # widgetspace_imp               is from   src/lib/x-kit/widget/space/widget/widgetspace-imp.pkg

    #    
    package gtg =  guiboss_to_guishim;                          # guiboss_to_guishim            is from   src/lib/x-kit/widget/theme/guiboss-to-guishim.pkg

    package b2s =  spritespace_to_sprite;                       # spritespace_to_sprite         is from   src/lib/x-kit/widget/space/sprite/spritespace-to-sprite.pkg
    package c2o =  objectspace_to_object;                       # objectspace_to_object         is from   src/lib/x-kit/widget/space/object/objectspace-to-object.pkg

    package s2b =  sprite_to_spritespace;                       # sprite_to_spritespace         is from   src/lib/x-kit/widget/space/sprite/sprite-to-spritespace.pkg
    package o2c =  object_to_objectspace;                       # object_to_objectspace         is from   src/lib/x-kit/widget/space/object/object-to-objectspace.pkg

    package g2p =  gadget_to_pixmap;                            # gadget_to_pixmap              is from   src/lib/x-kit/widget/theme/gadget-to-pixmap.pkg
    package m2d =  mode_to_drawpane;                            # mode_to_drawpane              is from   src/lib/x-kit/widget/edit/mode-to-drawpane.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 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 e2g =  millboss_to_guiboss;                         # millboss_to_guiboss           is from   src/lib/x-kit/widget/edit/millboss-to-guiboss.pkg

    package mt  =  millboss_types;                              # millboss_types                is from   src/lib/x-kit/widget/edit/millboss-types.pkg
    package fm  =  fundamental_mode;                            # fundamental_mode              is from   src/lib/x-kit/widget/edit/fundamental-mode.pkg

#   package que =  queue;                                       # queue                         is from   src/lib/src/queue.pkg
    package nl  =  red_black_numbered_list;                     # red_black_numbered_list       is from   src/lib/src/red-black-numbered-list.pkg

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

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

herein

    package minimill_mode {                                     # 
        #
        exception MINIMILL_MODE__STATE;                                                                         # Our per-pane persistent state (currently none).

        fun input_done          (arg:           mt::Editfn_In)                                                  # We bind this to RET to signal when minimill string entry is complete.
            :                                   mt::Editfn_Out
            =
            {   arg ->    { args:                       List( mt::Prompted_Arg ),                               # Args read interactively from user per our __editfn.args spec.
                            textlines:                  mt::Textlines,
                            point:                      g2d::Point,                                             # As in Point_And_Mark.
                            mark:                       Null_Or(g2d::Point),                                    # 
                            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.
                            readonly:                   Bool,                                                   # TRUE iff contents of textmill are currently marked as read-only.
                            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.
                            edit_history:               mt::Edit_History,                                       # Recent visible states of textmill, to support undo functionality.
                            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.
                            widget_to_guiboss:          gt::Widget_To_Guiboss,                                  # 
                            mill_to_millboss:           mt::Mill_To_Millboss,
                            #
                            mainmill_modestate:         mt::Panemode_State,                                     # Any persistent per-mode state (e.g., private state for fundamental-mode.pkg) for main mill is available via this.
                            minimill_modestate:         mt::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:       mt::Textpane_To_Textmill,                               # NB: We're running in textmill's microthread to guarantee atomicity, so invoking blocking textpane_to_textmill.* fns is likely to deadlock.
                            mode_to_drawpane:           Null_Or( m2d::Mode_To_Drawpane ),                       # This will be non-NULL iff we specified a non-NULL draw_*_fn in our mt::PANEMODE value at bottom of file (which we do not do in this package).
                            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.
                          };

                WORK  [ mt::MARK NULL,
                        mt::STRING_ENTRY_COMPLETE                                                               # Special hack just for input_done which signals that interactive entry of an INCREMENTAL_STRING is complete.
                      ];
            };
        input_done__editfn
            =
            mt::EDITFN (
              mt::PLAIN_EDITFN
                {
                  name   =>  "input_done",
                  doc    =>  "Interactive entry of string in minimill is complete -- harvest the string and reset to display modeline instead of minimill.",
                  args   =>  [],
                  editfn =>  input_done
                }
              );                                my _ =
        mt::note_editfn  input_done__editfn;

        fun tab_completion      (arg:           mt::Editfn_In)                                                  # We bind this to RET to signal when minimill string entry is complete.
            :                                   mt::Editfn_Out
            =
            {   arg ->    { args:                       List( mt::Prompted_Arg ),                               # Args read interactively from user per our __editfn.args spec.
                            textlines:                  mt::Textlines,
                            point:                      g2d::Point,                                             # As in Point_And_Mark.
                            mark:                       Null_Or(g2d::Point),                                    # 
                            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.
                            readonly:                   Bool,                                                   # TRUE iff contents of textmill are currently marked as read-only.
                            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.
                            edit_history:               mt::Edit_History,                                       # Recent visible states of textmill, to support undo functionality.
                            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.
                            widget_to_guiboss:          gt::Widget_To_Guiboss,                                  # 
                            mill_to_millboss:           mt::Mill_To_Millboss,
                            #
                            mainmill_modestate:         mt::Panemode_State,                                     # Any persistent per-mode state (e.g., private state for fundamental-mode.pkg) for main mill is available via this.
                            minimill_modestate:         mt::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:       mt::Textpane_To_Textmill,
                            mode_to_drawpane:           Null_Or( m2d::Mode_To_Drawpane ),                       # This will be non-NULL iff we specified a non-NULL draw_*_fn in our mt::PANEMODE value at bottom of file (which we do not do in this package).
                            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.
                          };

                case valid_completions
                    #
                    THE valid_completions
                        =>
                        {
                            line0 = mt::findline (textlines, 0);                                                # Get line containing text to tab-complete.  (minimill/modeline contains exactly one line, always line 0.)

                            chomped_line0  =  string::chomp  line0;                                             # Drop terminal newline (if any).

                            candidates     =  valid_completions  chomped_line0;

                            case candidates
                                #
                                [] =>   WORK  [];                                                               # No commandnames begin with chomped_line0 so do nothing.

                                _  =>   {   first = list::head candidates;
                                            final = list::last candidates;

                                            completion  =  string::longest_common_prefix  (first, final);       # We're depending here on the fact that 'candidates' is sorted alphabetically.

                                            completion  =  completion + (line0 == chomped_line0 ?? "" :: "\n"); # Add a terminal newline if original line had one.  I don't think this will ever be the case here, but let's stick with our general line-editing idiom.

                                            completion' =  mt::MONOLINE   { string =>  completion,
                                                                            prefix =>  NULL
                                                                          };

                                            textlines = nl::remove (textlines, 0);                              # Synthesize new 'textlines' with line replaced.
                                            textlines = nl::set    (textlines, 0, completion');

                                            (string::expand_tabs_and_control_chars                              # Now to compute end-of-line screencol -- new position for cursor.  This will be tricky only if 'completion' contains multibyte utf8 chars, which is currently unlikely, but let us be future-proof here:
                                              {
                                                utf8text        =>  completion,
                                                startcol        =>  0,
                                                screencol1      => -1,                                          # Don't-care.
                                                screencol2      => -1,                                          # Don't-care.
                                                utf8byte        => -1                                           # Don't-care.
                                              })
                                              ->
                                              { screentext_length_in_screencols => cols,
                                                ...
                                              };

                                            WORK  [ mt::TEXTLINES textlines,
                                                    mt::POINT     { row => 0,  col => cols }
                                                  ];
                                        };
                            esac;
                        };

                    NULL  =>
                        {
                            WORK  [                                                                             # User is entering a string for which we don't know the set of valid values, so ignore tab-completion attempt.
                                  ];
                        };
                esac;

            };
        tab_completion__editfn
            =
            mt::EDITFN (
              mt::PLAIN_EDITFN
                {
                  name   =>  "tab_completion",
                  doc    =>  "Attempt to complete string being interactively entered in buffer.",
                  args   =>  [],
                  editfn =>  tab_completion
                }
              );                                my _ =
        mt::note_editfn  tab_completion__editfn;


        minimill_mode_keymap
            =
            keymap
            where
                keymap = mt::empty_keymap;
                #
                keymap = mt::add_editfn_to_keymap (keymap, [ "RET"              ],      input_done__editfn              );
                keymap = mt::add_editfn_to_keymap (keymap, [ "TAB"              ],      tab_completion__editfn          );
            end;

        stipulate
            #                                                                                                   # Initialize state for the minimill-mode part of a textpane at startup.
            fun initialize_panemode_state                                                                       # Our canonical call is from textpane::startup_fn().            # textpane      is from   src/lib/x-kit/widget/edit/textpane.pkg
                  (                                                                                             # To maintain system-global state for mode use the guiboss_types::Gadget_To_Guiboss fns note_global, find_global, drop_global.
                    panemode:                           mt::Panemode,                                           # This will be minimill_mode (below).
                    panemode_state:                     mt::Panemode_State,                                     #
                    textmill_extension:                 Null_Or( mt::Textmill_Extension ),                      #
                    panemode_initialization_options:    List(    mt::Panemode_Initialization_Option )           #
                  )
                  :             (       mt::Panemode_State,
                                        Null_Or( mt::Textmill_Extension ),
                                        List(    mt::Panemode_Initialization_Option )
                                )
                =
                {   val =   { id   =>  issue_unique_id (),                                                      # Construct our state.
                              type => "minimill_mode::MINIMILL__STATE",
                              info => "State for minimill-mode.pkg fns",
                              data => MINIMILL_MODE__STATE
                            };

                    key = val.type;                                                                             # Enter our state into given mt::Panemode_State.
                    #                                                                                           #
                    panemode_state                                                                              #
                      =                                                                                         #
                      { mode => panemode_state.mode,                                                            #
                        data => sm::set (panemode_state.data, key, val)                                         #
                      };                                                                                        #

                    panemode ->  mt::PANEMODE  mm;                                                              # Let our parent panemodes also initialize.
                    #
                    case mm.parent
                        #
                        THE (parent as mt::PANEMODE p) =>  p.initialize_panemode_state (parent, panemode_state, textmill_extension, panemode_initialization_options);
                        NULL                           =>                                      (panemode_state, textmill_extension, panemode_initialization_options);
                    esac;
                };

            fun finalize_state
                  (
                    panemode:           mt::Panemode,                                                           # This will be minimill_mode (below).
                    panemode_state:     mt::Panemode_State
                  )
                  :                     Void
                =
                {   panemode ->  mt::PANEMODE  mm;                                                              # Let our parent panemodes also finalize.
                    #
                    case mm.parent
                        #
                        THE (parent as mt::PANEMODE p) =>  p.finalize_state (parent, panemode_state);
                        NULL                           =>                   (                      );
                    esac;
                };
        herein            

            minimill_mode
                =
                mt::PANEMODE
                  {
                    id     =>   issue_unique_id (),
                    name   =>   "Minimill",
                    doc    =>   "Textmill specialized for minimill text entry.",

                    keymap =>   REF minimill_mode_keymap,
                    parent =>   THE fm::fundamental_mode,

                    self_insert_command =>      fm::self_insert_command__editfn,

                    initialize_panemode_state,
                    finalize_state,

                    drawpane_startup_fn           => NULL,
                    drawpane_shutdown_fn          => NULL,
                    drawpane_initialize_gadget_fn => NULL,
                    drawpane_redraw_request_fn    => NULL,
                    drawpane_mouse_click_fn       => NULL,
                    drawpane_mouse_drag_fn        => NULL,
                    drawpane_mouse_transit_fn     => NULL
                  };
        end;
    };

end;





Comments and suggestions to: bugs@mythryl.org

PreviousUpNext