## dired-mode.pkg
#
# Mode for interactive display and manipulation of a directory,
# inspired by emacs' dired-mode.
#
# THIS IS CURRENTLY JUST A PLACEHOLDER AWAITING IMPLEMENTATION.
#
# 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/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 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 #
# XXX SUCKO FIXME Does this need to be __premicrothread' for any reason???
package fil = file__premicrothread; # file__premicrothread is from
src/lib/std/src/posix/file--premicrothread.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 # compiler is from
src/lib/core/compiler/compiler.pkg package err = compiler::error_message; # error_message is from
src/lib/compiler/front/basics/errormsg/error-message.pkg package sci = compiler::sourcecode_info; # sourcecode_info is from
src/lib/compiler/front/basics/source/sourcecode-info.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 idm = id_map; # id_map is from
src/lib/src/id-map.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 gtj = guiboss_types_junk; # guiboss_types_junk is from
src/lib/x-kit/widget/gui/guiboss-types-junk.pkg package frm = frame; # frame is from
src/lib/x-kit/widget/leaf/frame.pkg package sl = screenline; # screenline is from
src/lib/x-kit/widget/edit/screenline.pkg package p2l = textpane_to_screenline; # textpane_to_screenline is from
src/lib/x-kit/widget/edit/textpane-to-screenline.pkg package wt = widget_theme; # widget_theme is from
src/lib/x-kit/widget/theme/widget/widget-theme.pkg # compiler is from
src/lib/core/compiler/compiler.pkg package cs = compiler::compiler_state; # compiler_state is from
src/lib/compiler/toplevel/interact/compiler-state.pkg package ds = compiler::deep_syntax; # deep_syntax is from
src/lib/compiler/front/typer-stuff/deep-syntax/deep-syntax.pkg package em = dired_mill; # dired_mill is from
src/lib/x-kit/widget/edit/dired-mill.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 mm = minimill_mode; # minimill_mode is from
src/lib/x-kit/widget/edit/minimill-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 package ml = makelib; # makelib is from
src/lib/core/makelib/makelib.pkg package ci = compile_imp; # compile_imp is from
src/lib/x-kit/widget/edit/compile-imp.pkg package psx = posixlib; # posixlib is from
src/lib/std/src/psx/posixlib.pkg tracefile = "widget-unit-test.trace.log";
nb = log::note_on_stderr; # log is from
src/lib/std/src/log.pkg# Temporary test code:
stdout_redirect = psx::stdout_redirect;
stderr_redirect = psx::stderr_redirect;
Dummy1 = ci::Compile_Option; # XXX SUCKO FIXME temporary hack to ensure ci compiles during early development.
herein
package dired_mode { #
#
exception DIRED_MODE__STATE; # Our per-pane persistent state (currently none).
# Note that our dired_mill half DOES have private state -- see Dired_Mill_State in
src/lib/x-kit/widget/edit/dired-mill.pkg # Wee access that via the editfn 'mill_extension_state' field -- see below.
fun input_done (arg: mt::Editfn_In) # We bind this to RET to signal when dired-buffer code 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.
};
nb {. sprintf "input_done/AAA -- dired-mode.pkg"; };
dired_mill_state
=
em::decrypt__dired_mill_state mill_extension_state;
nb {. sprintf "input_done/BBB -- dired-mode.pkg"; };
dired_mill_state # Much of the following logic is adapted from read_eval_print_from_user() in
src/lib/compiler/toplevel/interact/read-eval-print-loop-g.pkg -> # Putting it here allows customization of the logic without having to frig with
src/lib/compiler/toplevel/interact/read-eval-print-loop-g.pkg { compiler_state_stack: Ref ((cs::Compiler_State, List(cs::Compiler_State)))
};
(pp::make_standard_prettyprinter_into_buffer [])
->
{ pp, get_buffer_contents_and_clear_buffer };
exception END_OF_FILE;
WORK [
];
};
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 dired (arg: mt::Editfn_In) # Interactive user command to start up an dired-mode pane onto an dired-mill -- an interactive facility supporting interactive evaluation of Mythryl.
: 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.
};
nb {. sprintf "dired/AAA --dired-mode.pkg"; };
# dired_mill_state # DO NOT DO THIS!
# = # 'dired' is run from an arbitrary pane in order to start up an dired mill+pane, so it is most unlikely that 'mill_extension_state' here will be an dired-mill state.
# em::decrypt__dired_mill_state mill_extension_state; # -- Voice Of Experience
nb {. sprintf "dired/BBB --dired-mode.pkg"; };
mainmill_modestate.mode
->
mt::PANEMODE pm;
mill_to_millboss #
-> #
mt::MILL_TO_MILLBOSS m2m;
textpane_to_textmill'
=
m2m.get_or_make_textmill # It should be OK if millboss-imp finds a mill of an unexpected textmill_extension here
# # because we're going to construct the pane for it via textpane_to_textmill.app_to_mill.make_pane_guiplan().
{ name => "*dired*",
#
textmill_options => [ mt::TEXTMILL_EXTENSION em::dired_mill
]
}
: mt::Textpane_To_Textmill
;
textpane_to_textmill'
->
mt::TEXTPANE_TO_TEXTMILL t2t;
t2t.app_to_mill
->
mt::APP_TO_MILL a2m;
a2m.pass_pane_guiplan to {.
#
pane_guiplan = #guiplan;
do_while_not {. # Repeat guipith edit until it takes. This is needed because other concurrent microthreads may be
# # attempting overlapping guipith edits with us. This avoids deadlock at a (tiny) risk of livelock.
get_guipiths = widget_to_guiboss.g.get_guipiths;
install_updated_guipiths = widget_to_guiboss.g.install_updated_guipiths;
(get_guipiths ())
->
(gui_version, guipiths)
#
: (Int, idm::Map( gt::Xi_Hostwindow_Info ))
;
guipiths = gtj::guipith_map (guipiths, options)
where
fun do_widget (w: gt::Xi_Widget_Type): gt::Xi_Widget_Type
=
case w
#
gt::XI_FRAME
{ id: Id,
frame_widget: gt::Xi_Widget_Type, # Widget which will draw the frame surround.
widget: gt::Xi_Widget_Type # Widget-tree to draw surrounded by frame.
}
=>
case frame_widget
#
gt::XI_WIDGET
{
widget_id: Id,
widget_layout_hint: gt::Widget_Layout_Hint,
doc: String # Debugging support: Allow XI_WIDGETs to be distinguishable for debug-display purposes.
}
=>
if (not (same_id (widget_id, pane_id)))
#
w;
else
gt::XI_GUIPLAN pane_guiplan; # Replace current pane with new one displaying new mill.
fi; # The a2m.make_pane_guiplan here is a wrapped version of the make_pane_guiplan() in this file.
_ => w;
esac;
_ => w;
esac;
options = [ gtj::XI_WIDGET_TYPE_MAP_FN do_widget ]
#
: List( gtj::Guipith_Map_Option )
;
end;
install_updated_guipiths # If this returns FALSE we'll loop and retry.
#
(gui_version, guipiths);
};
}; # do_while_not
WORK [
];
};
dired__editfn
=
mt::EDITFN (
mt::PLAIN_EDITFN
{
name => "dired",
doc => "Open an dired-mode pane onto an dired-mill instance.",
args => [],
editfn => dired
}
); my _ =
mt::note_editfn dired__editfn;
my _ =
nb {. sprintf "dired__editfn registered --dired-mode.pkg"; };
dired_mode_keymap
=
keymap
where
keymap = mt::empty_keymap;
#
keymap = mt::add_editfn_to_keymap (keymap, [ "RET" ], input_done__editfn );
end;
stipulate
# # Initialize state for the dired-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 dired_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 => "dired_mode::DIRED_MODE__STATE",
info => "State for dired-mode.pkg fns",
data => DIRED_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 dired_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
dired_mode
=
mt::PANEMODE
{
id => issue_unique_id (),
name => "Dired",
doc => "Interactive Mythryl evaluation.",
keymap => REF dired_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;
fun make_pane_guiplan # Synthesize a pane to display textmill's state. We get invoked by above gt::XI_GUIPLAN (make_pane_guiplan ()).
{ # At the moment this is (nearly) a clone of make_textpane::make_pane_guiplan(); if it doesn't diverge we should probably just generalize that fn.
textpane_to_textmill: mt::Textpane_To_Textmill, #
filepath: Null_Or( String ), # make_pane_guiplan should select the pane mode to use based on the filename, but we do not yet do this. XXX SUCKO FIXME.
textpane_hint: Crypt
}
: gt::Gp_Widget_Type
=
{
minipanemode = mm::minimill_mode;
mainpanemode = dired_mode;
screenlines_mark = issue_unique_id ();
textpane_id = issue_unique_id ();
textmill_spec = mt::OLD_TEXTMILL_BY_PORT textpane_to_textmill;
gt::FRAME
( [ gt::FRAME_WIDGET (textpane::with { textpane_id,
screenlines_mark,
textmill_spec,
minipanemode,
mainpanemode,
options => [ ]
}
)
],
gt::COL
[
gt::MARK'
( screenlines_mark,
"Screenlines",
gt::COL
[
screenline::with
{
paneline => 0,
textpane_id,
options => [ sl::DOC "Screenline 1",
sl::PIXELS_HIGH_MIN 0,
sl::STATE { cursor_at => p2l::NO_CURSOR,
selected => NULL,
text => "I am a screenline",
prompt => "",
screencol0 => 0,
background => rgb::white
}
]
}
]
),
gt::FRAME
( [ gt::FRAME_WIDGET (frame::with [ frm::FRAME_RELIEF wt::RAISED ]) ],
#
screenline::with
{
paneline => -1,
textpane_id,
options => [ sl::DOC "Modeline (Screenline -1)",
sl::PIXELS_HIGH_MIN 16,
sl::PIXELS_HIGH_CUT 0.0,
#
sl::STATE { cursor_at => p2l::NO_CURSOR,
selected => NULL,
text => "Modeline (Screenline -1)",
prompt => "",
screencol0 => 0,
background => rgb::white
}
]
}
)
]
);
};
my _ =
em::make_pane_guiplan__hack
:=
make_pane_guiplan;
};
end;