Subject: bug#22873: Can we support multiple cursors?

From: Keith David Bershatsky <[email-masked]>
Date: Thu, 10 Aug 2017 17:00:33 -0700

PATCH VERSION:  010

-  This patch applies to commit a30e7e12ed8465e2565dd318d921bc87f52ce18e from 03/28/2016.  [@lawlist is presently unable to use the current master branch for daily workflow due to certain unrelated bugs.]

WHAT'S NEW:

-  `update_frame` runs too late in the redisplay cycle to reliably remove all fake cursors when cutting/pasting text in conjunction with the current command loop.  If we erase the fake cursors at the outset of `redisplay_window`, removal occurs too early in the redisplay cycle and the user sees the cursors being removed before the current command finishes.  The very end of `redisplay_window` is a little closer to being the "sweet spot" for initial fake cursor removal, which is where it now occurs.  Fake cursors are presently only being drawn whenever `update_frame` is called.  Removal of fake cursors is faster on OSX, and slower on Windows and X11.

-  Recordation of prior values at the end of `redisplay_window` has been simplified to just four (4) values (current/previous window-start/window-end).

-  `mc_erase` has been simplified to use the existing function `erase_phys_cursor`.

-  Miscellaneous bug fixes, including, but not limited to checks to ensure that coordinates (X, Y, HPOS, VPOS) are within bounds.

-  Improved comments and doc-strings.

TODO:

-  Set up a user option similar to `cursor-in-non-selected-windows'.

-  Explore the idea of whether we need additional code to handle removing/redrawing
   fake cursors when windows change sizes / layouts.

-  `w->phys_cursor.vpos` of the real cursor is accurate as to VPOS irrespective of
   whether the `header-line-format' exists.  `mc_x_y_hpos_vpos' may need to adopt
   a similar approach as to VPOS instead of checking the `header-line-format'
   and potentially adding a value of 1 immediately before calling `mc_erase' / `mc_draw'.

-  Fake cursors are being redrawn too often when mousing over text (underneath the
   real cursor) with mouse-face properties, and also when non-selected windows/frames
   have an ongoing process that require frequent redisplay updates.

-  Optimize drawing/erasing fake cursors.

-  Implement a way to properly calculate X, Y, HPOS, VPOS when overlays are present.
   The overlay after-string wreaks havoc when calculating coordinates.

-  Fix any bugs (there will surely be many).

-  Try and convince one or more real programmers to take over from here.

ROAD MAP:

-  The first stage of development is the creation and removal of fake cursors,
   which are specified with:  buffer point, cursor-style, and cursor color.

-  The second stage of development is the built-in C implementation of functionality
   similar to the multiple cursors library by Magnar Sveen.

INSTALLATION:

-  STEP #1 (clone master branch):  git clone -b master git://git.sv.gnu.org/emacs.git

-  STEP #2:  cd over to the root of the `emacs` source directory cloned in the first step above.

-  STEP #3 (hard reset):  git reset --hard a30e7e12ed8465e2565dd318d921bc87f52ce18e

   The following message is displayed in the terminal:  "HEAD is now at a30e7e1 Mention the `M-q' changes"

-  STEP #4 (put the patch in place):  Copy the latest patch to the root of the emacs source directory cloned in the first step above.

-  STEP #5 (apply the patch):  git apply [latest-patch.diff]

-  STEP #6:  ./autogen.sh

-  STEP #7:  Configure the build for X, MS Windows, or OSX; e.g.,:  ./configure --with-ns

-  STEP #8:  make

-  STEP #9:  make install

-  STEP #10:  Launch the newly built Emacs, and copy the following function to the `*scratch*` buffer, and type `M-x mc-test`.

(defun mc-test ()
"Draw fake cursors at all POS defined in the `mc-list'.  Multiple fake cursors
are supported by GUI versions of Emacs built for X, Windows and OSX.
Popular forms of specifying colors such as \"red\" and \"#FF0000\" are now
supported, as well as LSL color vectors such as [1.0 0.0 0.0].  For those users
who choose the former familiar methods of specifying colors with strings,
`mc_color_vector_calculate' will convert those strings to LSL color vectors.
The color vectors are commonly referred to as LSL (The Linden Scripting Language).
`nsterm.m' uses `NSColor', which works well with LSL.  `w32term.c' uses
`PALETTERGB' or `RGB', and the conversion from LSL is done internally by
multiplying each element of the LSL color vector by 255.  `xterm.c' uses
`x_make_truecolor_pixel', which uses 16-bit RGB -- the conversion from LSL
happens internally by multiplying each element of the LSL color vector by 65535."
(interactive)
  (let ((buffer (get-buffer-create "*MC-TEST*")))
    (with-current-buffer buffer
      (erase-buffer)
      (insert "This is a test!")
      (setq mc-list '((1 "hbar" "red")
                      (2 "bar" "yellow")
                      (3 "box" "#00FF00")
                      (4 "hollow" "#0000FF")
                      (5 ("hbar" 3) [1.0 0.0 1.0])
                      (6 ("bar" 3) [0.0 1.0 1.0]))))
    (select-window (display-buffer buffer))
    ;;; The trigger in `keyboard.c` is not activated in this example, so we
    ;;; Force the multiple cursors to be drawn.
    (mc-draw-erase (selected-window))))