## 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.sublibstipulate
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.pkgherein
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;