[Date Prev][Date Next][Thread Prev][Thread Next][Author Index][Date Index][Thread Index]
:zz: SHEAR MAGNIFICENCE! (Was: PATCH: Shear function and useful selection operations
- To: zzdev@xxxxxxxxxx
- Subject: :zz: SHEAR MAGNIFICENCE! (Was: PATCH: Shear function and useful selection operations
- From: Ted Nelson <ted@xxxxxxxxxx>
- Date: Thu, 29 Oct 1998 21:40:09 +0900
- Cc: ted@xxxxxxxxxxxxxx
- In-reply-to: <19981029071449.18612.qmail@xxxxxxxxxx>
- Reply-to: zzdev@xxxxxxxxxx
I'm speechless.
Will study it and reply next week. Looks wonderful.
Best, Ted
At 02:14 AM 10/29/98 -0500, you wrote:
>
>The enclosed patch implements the following functions:
>
>I. The `shear' function is implemented.
>
> A. I replaced the #Shear action cell with four related shear action
> cells. They are:
>
> #Shear -^
> #Shear -v
> #Shear ^+
> #Shear v+
>
> All shear action cells operate on the vertical rank headed by
> cursor 1. We'll take ^+ as an example. The + sign means that
> the rank to be moved will have its Right links detached and
> reattached; if it were a - we would detach the Left links
> instead. The ^ means that the cells will be moved down one step
> each; if it were v we would move them up instead. (We'll see
> why up and down are reversed in a minute.)
>
> Here is an example:
>
> A1 -- B1
> |
> A2 -- B2
> |
> A3
> |
> A4 -- B4
> |
> A5 -- B5
>
> Suppose cursor 1 is on cell A1. After the ^+ shear, the links
> are like this:
>
> A1 -- B2
> |
> A2
> |
> A3 -- B4
> |
> A4 -- B5
> |
> A5 -- B1
>
> The A1...A5 have all moved down one step. A1 is linked to the
> cell that A2 used to be linked to. A2 is linked to the cell
> that A3 used to be linked to (none). A3 is linked to the cell
> that A4 used to be linked to, etc. A5 has wrapped around and is
> now linked to the cell that A1 used to be linked to. (This
> `wrap' behavior is optional.)
>
> Since the cursor is still on A1, it looks as though the B column
> moved up instead of the A column moving down. That's why ^+
> means to shear down instead of to shear up: What you see on
> the screen is an upward movement in the B column, even though
> the real truth is that the A column moved down.
>
> Caution: If the cursor had been on A3, only the links from A3,
> A4, and A5 would have changed. This is because the accursed
> cell is the *head* of the rank that shears. The result would
> look like this:
>
> A1 -- B1
> |
> A2 -- B2
> |
> A3 -- B4
> |
> A4 -- B5
> |
> A5
>
> We may want to change this behavior. It is sometimes
> counterintuitive. For example, if the cursor is on A1 and we
> shear up, nothing will happen, because A1 is already at the top
> of the rank. It gets disconnected from B1, and then `wraps
> around' and reconnects to B1.
>
> B. Shearing is implemented internally by the `do_shear' function.
> This inaugurates a new series of functions named do_*.
>
> do_shear accepts between three and five arguments:
>
> do_shear($first_cell, $shear_dim, $link_dim, $n, $hang);
>
> The last two are optional. $first_cell is the head of the rank
> that is sheared. $shear_dim is the dimension in which the rank
> extends. For example, if $shear_dim is +d.1, then all the cells
> +d.1ward from $first_cell will be sheared.
>
> $link_dim is the dimension of the links that are broken and
> relinked. If $shear_dim is +d.1 and $link_dim is +d.2, then the
> +d.2 links from all the cells in the sheared rank will be
> broken, and each cell in the rank will be re-linked to the cell
> that was formerly +d.1+d.2 from it, if there was such a cell.
>
> $n says how many steps to shear. If absent, it defaults to 1.
>
> If $hang is a true value, then the last cell in the rank will be
> left unlinked instead of wrapping around to the beginning.
>
>
> C. The function `atcursor_shear($number, $sheardir, $linkdir)'
> shears cells in window #$number. The sheared cells are the
> rank starting at cursor #$number in the $sheardir direction.
> Their $linkdir links are detached and reattached.
>
> $sheardir and $linkdir must each one of L, R, U, D, I, or O.
>
>II. Cell marking is improved.
>
> A. ZigZag now supports arbitrarily many `selections'. A selection
> is a set of marked cells. Initially, there is one selection,
> called the `active selection' or `selection zero'. The cells
> that are considered `marked' are those in the active selection
> and are displayed specially.
>
> B. A cell is in the active selection when it is linked +d.markward
> from the $SELECT_HOME, which is cell 21. The default
> ZigZagSpace initializes cell 21 to contain the word `Selection'.
>
> C. The user can select or unselect a cell with the `m' and `M'
> commands as before. These add the accursed cell in window 1 or
> window 0 to the active selection by inserting it +d.markward
> from $SELECT_HOME. If the cell is already in the active
> selection, it is removed from the $SELECT_HOME+d.mark rank.
>
> D. The key sequence `meta-M' creates a new selection and saves the
> active selection in it. It then makes the active selection
> empty. The new selection gets a name like `Selection #1' or
> `Selection #2'.
>
> E. Inactive selections are linked d.2ward from $SELECT_HOME.
> Each has a special cell which heads a +d.markward rank which
> includes all the cells in the selection it represents. The
> head cells of all the selections form a ring rank in dimension
> d.2.
>
> F. The key sequence `meta-m' shears the selection space d.2ward so
> that what used to be selection #2 becomes selection #1, what
> used to be selection #1 becomes the active selection, and what
> used to be the active selection becomes some high-numbered
> selection. In this way, the user can manage several different
> selected sets. One selection might be the set of all the
> Monarchs in the geneaology, and another might be the set of all
> the cells that represent red things. The user can make any
> selection active with `meta-m', and can then add cells to it or
> remove cells from it with `m' and `M'.
>
> G. I expect that we will provide operations that apply to
> selections. For example ``Intersect these two selections.''
> ``Remove all the cells in selection #X from selection #Y.''
> ``Select all the cells in a certain rank.'' ``Select all the
> cells that can be reached from here.''
>
> H. Because of the way I organized the selection structure, no cell
> can be in two selections at once. This is a bug.
>
> I. I renamed all the *_mark functions to *_select.
>
> J. There is a new function, `rotate_selection', which shears the
> selection space +d.2wards to cycle through the selections.
> It takes no arguments, but it does check the input buffer for a
> number. If present, the number says how many notches to turn
> the selection wheel; the default is 1.
>
> K. There is a new function, `push_selection', which creates a new
> selection head and pushes it into the $SELECTION_HOME+d.2 rank.
> After it does this, it shears the selection space so that the
> old active selection is attached to the new head, and the
> active selection head, $SELECT_HOME, is selecting nothing.
>
> L. There is a new action note, `#Rot.Selection', which invokes the
> `rotate_selection' command.
>
>III. Miscellaneous utilities.
>
> A. The function `get_accursed($number)' returns the accursed cell
> in the specified window.
>
> B. The function `cells_row($head, $dimension)' returns a list of
> all the cells in the rank that starts at cell $head and
> continues in the direction specified by $dimension. It behaves
> properly in the presence of rings.
>
> In scalar context, it returns the number of cells in the rank.
>
>
>
>The patch:
>
>--- zigzag.55 Tue Oct 27 22:55:17 1998
>+++ zigzag Thu Oct 29 01:26:21 1998
>@@ -29,7 +29,7 @@
> #
> # $Log: zigzag,v $
> # Revision 0.55 1998/10/26 05:37:32 xanni
>-# Change default file extension and incorporate EDITOR selection patch
>+# Change default file extension and incorporate $EDITOR selection patch
> # from Mark-Jason Dominus <mjd@xxxxxxxxxx>
> #
> # Revision 0.54 1998/10/08 03:56:21 xanni
>@@ -88,6 +88,7 @@
> my $CELLS_PER_WIN = 5; # Number of cells displayed across each
window
> my $CURSOR_HOME = 10; # NOTE! This assumes it stays fixed!
> my $DELETE_HOME = 99; # NOTE! This assumes it stays fixed!
>+my $SELECT_HOME = 21; # NOTE! This assumes it stays fixed!
> my $EDITOR = choose_editor();
> my $FILENAME = "zigzag.zz"; # Default filename for initial slice
> my $TEMP_FILE = "/tmp/zigzag-$<-$^T"; # Filename used for external editing
>@@ -171,13 +172,15 @@
> "N" => 'cell_create(0);',
> &KEY_IC => 'cell_create(0);',
> "n" => 'cell_create(1);',
>- "M" => 'atcursor_mark(0);',
>- "m" => 'atcursor_mark(1);',
>+ "M" => 'atcursor_select(0);',
>+ "m" => 'atcursor_select(1);',
>+ &meta_key("m") => 'rotate_selection()',
>+ &meta_key("M") => 'push_selection()',
> "Q" => 'view_quadrant_toggle(0);',
> "q" => 'view_quadrant_toggle(1);',
> "R" => 'view_reset(0);',
> "r" => 'view_reset(1);',
> "T" => 'atcursor_clone(0);',
> "t" => 'atcursor_clone(1);',
> "V" => 'view_raster_toggle(0);',
>@@ -236,6 +239,7 @@
> 10 => "Cursor home",
> "10+d.1" => 1,
> "10+d.2" => 11,
>+ "10-d.1" => 21,
> 11 => "Action",
> "11+d.1" => 12,
> "11-d.2" => 10,
>@@ -268,6 +272,10 @@
> "19+d.1" => 20,
> 20 => "I",
> "20-d.1" => 19,
>+ 21 => "Selection",
>+ "21+d.1" => 10,
>+ "21+d.2" => 21,
>+ "21-d.2" => 21,
> 30 => "#Edit\natcursor_edit(1);",
> "30+d.1" => 35,
> "30-d.2" => 0,
>@@ -313,9 +321,12 @@
> "55+d.1" => 56,
> 56 => "#O-break\natcursor_break_link(1, 'O');",
> "56-d.1" => 55,
>- 60 => "#Mark\natcursor_mark(1);",
>+ 60 => "#Select\natcursor_select(1);",
> "60-d.2" => 50,
> "60+d.2" => 70,
>+ "60+d.1" => 61,
>+ 61 => "#Rot.Selection\nrotate_selection();",
>+ "61-d.1" => 60,
> 70 => "#L-Hop\natcursor_hop(1, 'L');",
> "70+d.1" => 71,
> "70-d.2" => 60,
>@@ -334,9 +345,18 @@
> "74+d.1" => 75,
> 75 => "#O-Hop\natcursor_hop(1, 'O');",
> "75-d.1" => 74,
>- 80 => "#Shear",
>+ 80 => "#Shear -^\natcursor_shear(1, 'D', 'L')",
> "80-d.2" => 70,
> "80+d.2" => 85,
>+ "80+d.1" => 81,
>+ 81 => "#Shear -v\natcursor_shear(1, 'U', 'L')",
>+ "81-d.1" => 80,
>+ "81+d.1" => 82,
>+ 82 => "#Shear ^+\natcursor_shear(1, 'D', 'R')",
>+ "82-d.1" => 81,
>+ "82+d.1" => 83,
>+ 83 => "#Shear v+\natcursor_shear(1, 'U', 'R')",
>+ "83-d.1" => 82,
> 85 => "#Chug",
> "85-d.2" => 80,
> "85+d.2" => 90,
>@@ -427,10 +447,11 @@
> return (defined($ZZ{"$cell-d.clone"}) || defined($ZZ{"$cell+d.clone"}));
> }
>
>-sub is_marked($)
>+sub is_selected($)
> {
> my $cell = shift;
>- return (defined($ZZ{"$cell-d.mark"}) || defined($ZZ{"$cell+d.mark"}));
>+ my $headcell = get_lastcell($cell, '-d.mark');
>+ return $headcell == $SELECT_HOME && $cell != $SELECT_HOME;
> }
>
>
>@@ -454,6 +475,15 @@
> # Retrieving Information
> # Named get_*
> #
>+
>+sub get_accursed($)
>+# Get the cell that is accursed in the specified window
>+# or by the specified cursor
>+{
>+ my $n = shift;
>+ &get_lastcell(&get_cursor($n), "-d.cursor");
>+}
>+
> sub get_lastcell($$)
> # Find the last cell along a given dimension
> {
>@@ -625,6 +655,79 @@
> return @_;
> }
>
>+#
>+# Multiple-cell operations
>+# Named do_*
>+#
>+sub do_shear($$$;$$)
>+# Given a row of cells starting at $first_cell,
>+# move them all $n cells in the $dir direction.
>+# Cells that were linked in the $link direction
>+# have their links broken and relinked to new cells.
>+#
>+# Before: do_shear(A1, d.1, d.2, 1);
>+#
>+# ---> d.1
>+# V d.2
>+#
>+# A1 --- B1 --- C1 --- D1 --- E1
>+# | | | |
>+# A2 B2 C2 D2 E2
>+#
>+# After:
>+#
>+# A1 --- B1 --- C1 --- D1 --- E1
>+# | | |
>+# A2 B2 C2 D2 E2
>+#
>+# Optional fourth argument $n defaults to 1.
>+# Optional fifth argument $hang says whether the cell on the end
>+# should be linked back at the beginning or whether it should just
>+# be left hanging. $hang=false: Back at beginning.
>+# $hang = true: Leave hanging. Default: false.
>+{
>+ my ($first_cell, $dir, $link, $n, $hang) = @_;
>+ $n = 1 unless defined $n;
>+ $hang = 0 unless defined $hang;
>+
>+ my $cell;
>+ my ($prev_cell, $prev_linked);
>+ my $first_linked = $ZZ{"$first_cell$link"};
>+
>+ my @shear_cells = &cells_row($first_cell, $dir);
>+ my @linked_cells = map {$ZZ{"$_$link"}} @shear_cells;
>+
>+ my @new_link = @linked_cells;
>+ # Move some of these from the beginning
>+ my @x = splice(@new_link, 0, $n);
>+ # And put them back at the end.
>+ push @new_link, @x;
>+
>+ my $i;
>+ my $linkno = 0;
>+ my $last_linked;
>+ # Break all the links
>+ for ($i=0; $i < @shear_cells; $i++) {
>+ my $old_link = $linked_cells[$i];
>+ next unless defined $old_link;
>+ my $shear_cell = $shear_cells[$i];
>+ link_break($shear_cell, $old_link, $link);
>+ }
>+
>+ $linkno = 0;
>+ for ($i=0; $i < @shear_cells; $i++) {
>+ my $new_link = $new_link[$i];
>+ next unless defined $new_link;
>+ next if $i == $#shear_cells && $hang;
>+ my $shear_cell = $shear_cells[$i];
>+ link_make($shear_cell, $new_link, $link);
>+ }
>+
>+ foreach (@Window_Dirty)
>+ {
>+ $_ = $TRUE;
>+ }
>+}
>
> #
> # Functions that operate on links between cells
>@@ -841,25 +944,52 @@
> }
> }
>
>-sub atcursor_mark($)
>-# mark the current cell
>+sub atcursor_select($)
>+# select or unselect the current cell
> {
> my $curs = &get_cursor($_[0]);
> my $cell = &get_lastcell($curs, "-d.cursor");
>
>- my $new = $ZZ{"n"}++;
>- $ZZ{$new} = "mark";
>- &cell_insert($new, $cell, "+d.mark");
>- &status_draw("Marked cell $cell");
>+ if (&is_selected($cell)) {
>+ &cell_excise($cell, "d.mark");
>+ &status_draw("Selected cell $cell");
>+ } else {
>+ &cell_insert($cell, $SELECT_HOME, "+d.mark");
>+ &status_draw("Selected cell $cell");
>+ }
> #&cursor_move_dimension($curs, "+d.mark");
>
>-
> foreach (@Window_Dirty)
> {
> $_ = $TRUE;
> }
> }
>
>+sub rotate_selection ()
>+# Exchange the current selection with one of the saved selections. If
>+# there's an input buffer, it holds the number of the desired
>+# selection, so shear all the selections +d.2ward by that many.
>+# (Selection #0 is currently active.) Otherwise, just shear by 1.
>+{
>+ my $shear_count = (defined($Input_Buffer) ? $Input_Buffer : 1);
>+# my $num_selections = &cells_row($SELECT_HOME, "+d.2");
>+
>+ do_shear($SELECT_HOME, '-d.2', '+d.mark', $shear_count);
>+}
>+
>+sub push_selection()
>+# Push the current selection onto the selection stack.
>+# All saved selections move +d.2ward one step.
>+# The current selection is now empty.
>+{
>+ my $new_sel = $ZZ{"n"}++;
>+ my $num_selections = &cells_row($SELECT_HOME, "+d.2");
>+ $ZZ{$new_sel} = "Selection #$num_selections";
>+ cell_insert($new_sel, $SELECT_HOME, "+d.2");
>+ do_shear($SELECT_HOME, "+d.2", "+d.mark", 1);
>+}
>+
>+
> sub atcursor_insert($$)
> # Insert a new cell at a given cursor in a given direction
> {
>@@ -988,6 +1118,25 @@
> }
> }
>
>+sub atcursor_shear($$$)
>+# Arguments: $curs = cursor/window number
>+# $sheardir = direction and +/-
>+# $linkdir = direction and +/-
>+# directions name axes. They get turned into dimensions
>+# for the do_shear call.
>+# Head cell of the shear is the accursed cell
>+{
>+ my ($number, $shear_dir, $link_dir) = @_;
>+
>+ my $cursor = &get_cursor($number);
>+ my $shear_dim = &get_dimension($cursor, $shear_dir);
>+ my $link_dim = &get_dimension($cursor, $link_dir);
>+
>+ my $headcell = &get_accursed($number);
>+
>+ &do_shear($headcell, $shear_dim, $link_dim, 1);
>+}
>+
> sub atcursor_edit($)
> # Invoke an external text editor to edit the cell under a given cursor
> {
>@@ -1156,6 +1305,22 @@
> unlink $TEMP_FILE;
> }
>
>+sub cells_row($$)
>+# Final all the cells in the row starting from $cell
>+# in the $dir dimension. Return a list or a count
>+# depending on calling context.
>+{
>+ my ($cell1, $dir) = @_;
>+ my $cell;
>+ my @result = ($cell1);
>+ for ($cell = $ZZ{"$cell1$dir"};
>+ defined($cell) && $cell != $cell1;
>+ $cell = $ZZ{"$cell$dir"}
>+ ) {
>+ push @result, $cell;
>+ }
>+ @result;
>+}
>
> #
> # Functions that operate on the whole screen
>@@ -1299,8 +1464,8 @@
> if (!$LOTS_OF_COLOURS && &is_clone($cell))
> { addch($win, $row - 1, $col, "c"); }
>
>- # Display marked-cell flag if we aren't using lots of colours
>- if (!$LOTS_OF_COLOURS && &is_marked($cell))
>+ # Display selected-cell flag if we aren't using lots of colours
>+ if (!$LOTS_OF_COLOURS && &is_selected($cell))
> { addch($win, $row - 1, $col, "m"); }
>
> # Display dimension guide
>@@ -1509,9 +1674,9 @@
> # Clone cells get a special colour in high-colour mode
> attron($win, COLOR_PAIR(2) | A_BOLD)
> if $LOTS_OF_COLOURS && &is_clone($cell);
>- # Ditto marked cells
>+ # Ditto selected cells
> attron($win, COLOR_PAIR(3) | A_BOLD)
>- if $LOTS_OF_COLOURS && &is_marked($cell);
>+ if $LOTS_OF_COLOURS && &is_selected($cell);
>
> # Colour/highlight the cursors
> attron($win, $Display_Has_Colour ? COLOR_PAIR(6) : A_UNDERLINE) if
$number == 1;
>@@ -1907,4 +2072,3 @@
> #
> # End.
> #
>-
>
>
>
>
>
>
____________________________________________________
Theodor Holm Nelson, Visiting Professor of Environmental Information
Keio University, Shonan Fujisawa Campus, Fujisawa, Japan
Home Fax from USA: 011-81-466-46-7368 (If in Japan, 0466-46-7368)
Professorial home page http://www.sfc.keio.ac.jp/~ted/
_____________________________________________________
Permanent: Project Xanadu, 3020 Bridgeway #295, Sausalito CA 94965
Tel. 415/ 331-4422, fax 415/332-0136
http://www.xanadu.net
PERMANENT E-MAIL: ted@xxxxxxxxxx
_____________________________________________________
Quotation of the day, 98.10.29:
Last words of Oscar Wilde: "Either that wallpaper goes, or I do."