Subject: Re: bug#22873: Can we support multiple Cursors?

From: Eli Zaretskii <[email-masked]>
Date: Wed, 09 Mar 2016 18:03:25 +0200

> Date: Tue, 08 Mar 2016 22:27:02 -0800
> From: Keith David Bershatsky <[email-masked]>
> Cc: [email-masked]
> 
> The second draft of the proposed feature for multiple fake cursors is attached.  For the record, I'm not a programmer -- just a hobbyist -- and the draft patch is not meant to be a proposed official patch -- it is just a working proof concept.  The patch contains a few extra things that I use for debugging and also for drawing my solid vertical line that tracks the cursor position.  It has been tested to some extent on Emacs built for OSX 10.6.8 and Windows XP (SP-3).  Different colors for each fake cursor have already been implemented on Emacs for OSX, but I haven't yet looked into how to accomplish that objective on Emacs for Windows.  The draft concept patch is for the master branch as of March 8, 2016 bearing commit "e0400b72a24d67b53f71c8b97915cae599e36c37".  After applying the patch, the new feature can be tested as follows:

Looks like quite a few of the changes in the patch are not really
related to multiple cursors.  Did you produce diffs for all of your
other local changes?

> diff --git a/src/buffer.h b/src/buffer.h
> index 5783bfb..01c3755 100644
> --- a/src/buffer.h
> +++ b/src/buffer.h
> @@ -643,6 +643,15 @@ struct buffer
>       cache are enabled.  See search.c, indent.c and bidi.c for details.  */
>    Lisp_Object cache_long_scans_;
>  
> +  /* The name of the hook.  */
> +  Lisp_Object window_start_end_hook_;
> +
> +  /* The name of list.  */
> +  Lisp_Object posn_list_;
> +
> +  /* The name of list used by multiple cursors for next redisplay.  */
> +  Lisp_Object mc_list_;
> +
>    /* If the width run cache is enabled, this table contains the
>       character widths width_run_cache (see above) assumes.  When we
>       do a thorough redisplay, we compare this against the buffer's
> @@ -885,6 +894,21 @@ struct buffer
>     buffer.  (Some setters that are private to a single .c file are
>     defined as static in those files.)  */
>  INLINE void
> +bset_window_start_end_hook (struct buffer *b, Lisp_Object val)
> +{
> +  b->window_start_end_hook_ = val;
> +}

The above inline function and the corresponding member of struct
buffer seems unrelated.

> diff --git a/src/keyboard.c b/src/keyboard.c
> index 4e1ac15..329cba0 100644
> --- a/src/keyboard.c
> +++ b/src/keyboard.c
> @@ -1244,6 +1244,15 @@ static int read_key_sequence (Lisp_Object *, int, Lisp_Object,
>                                bool, bool, bool, bool);
>  static void adjust_point_for_property (ptrdiff_t, bool);
>  
> +static void
> +set_window_start_end_hook (void)
> +{
> +  Lisp_Object window = (selected_window);
> +  struct window *w = decode_live_window (window);
> +  w->window_start_end_hook_force = true;
> +  w->window_start_end_hook_pending = true;
> +}
> +
>  Lisp_Object
>  command_loop_1 (void)
>  {
> @@ -1269,6 +1278,8 @@ command_loop_1 (void)
>        if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks))
>  	safe_run_hooks (Qpost_command_hook);
>  
> +      set_window_start_end_hook ();
> +
>        /* If displaying a message, resize the echo area window to fit
>  	 that message's size exactly.  */
>        if (!NILP (echo_area_buffer[0]))
> @@ -1485,6 +1496,8 @@ command_loop_1 (void)
>  
>        safe_run_hooks (Qpost_command_hook);
>  
> +      set_window_start_end_hook ();
> +
>        /* If displaying a message, resize the echo area window to fit
>  	 that message's size exactly.  */
>        if (!NILP (echo_area_buffer[0]))

Likewise.

> diff --git a/src/xdisp.c b/src/xdisp.c
> index 5b96144..102ac23 100644
> --- a/src/xdisp.c
> +++ b/src/xdisp.c
> @@ -13414,6 +13414,93 @@ do { if (! polling_stopped_here) stop_polling ();	\
>  do { if (polling_stopped_here) start_polling ();	\
>         polling_stopped_here = false; } while (false)
>  
> +static void
> +run_window_start_end_hook (Lisp_Object window, struct text_pos startp, EMACS_INT posint, struct it it, char *string, bool force)
> +{

Likewise.

> +    case 'w':
> +      {
> +  ptrdiff_t window_start = marker_position (w->start);
> +  pint2str (decode_mode_spec_buf, width, window_start);
> +  return decode_mode_spec_buf;
> +      }
> +
> +    case 'W':
> +      {
> +  ptrdiff_t window_end = BUF_Z (b) - w->window_end_pos;
> +  pint2str (decode_mode_spec_buf, width, window_end);
> +  return decode_mode_spec_buf;
> +      }
> +

Likewise.

> +static const char *
> +internal_line_number_at_position (struct window *w, register int c, int field_width, Lisp_Object *string)
> +{

Likewise.

> +DEFUN ("line-number-at-position", Fline_number_at_position, Sline_number_at_position, 1, 2, 0,
> +       doc: /* Return line number at position.  */)
> +  (Lisp_Object window, Lisp_Object pos)
> +{

Likewise.

Thanks.