ergoemacs / ergoemacs-mode

ergoemacs-mode
ergoemacs.github.io/
GNU General Public License v3.0
293 stars 35 forks source link

seems to be an incompatibility between ergoemacs-mode and multiple-cursors #342

Closed liefswanson closed 9 years ago

liefswanson commented 9 years ago

Hi there, I have been having a problem with compatibility between this mode and another called multiple-cursors.

I have already logged an issue with multiple cursors, but the developer isn't sure where to start looking for the incompatibility in the ergoemacs source. I was hoping to make it a collaborative effort, to figure out exactly why these two modes seem to be interfering with one another.

That issue can be found below, essentially ergoemacs seems to be messing with the pattern matching in multiple-cursors.

https://github.com/magnars/multiple-cursors.el/issues/191

Thanks for any assistance!

mattfidler commented 9 years ago

I'm not sure, but it may be related to unread command events

https://github.com/magnars/multiple-cursors.el/pull/145

I submitted a pull to make this work for me a while ago.

mattfidler commented 9 years ago

I tried to reproduce this error and I cannot. When I mark the buffer the following happens

[foo] bar bar bar foo bar

When I call the command 'mc/mark-next-like-this, the following is highlighted.

[foo] bar bar bar [foo] bar

However, I am using the "unstable" version of ergoemacs-mode.

mattfidler commented 9 years ago

My only guess, is it may be related to Issue #329

mattfidler commented 9 years ago

You can see if it works by adding the offending function to your .emacs startup:


(require 'package)
(add-to-list 'package-archives
             '("melpa" . "http://melpa.milkbox.net/packages/") t)
(package-initialize)

(require 'ergoemacs-mode)
(defun ergoemacs-read-key-call (function &optional record-flag keys)
  "`ergoemacs-mode' replacement for `call-interactively'.

This will call the function with the standard `call-interactively' unless:

- `ergoemacs-describe-key' is non-nil.  In this case,
   `describe-function' is called instead.

-  The function name matches \"self-insert\", then it will send the keys
   by `unread-command-events'.

In addition, when the function is called:

- Add the function count to `keyfreq-table' when `keyfreq-mode'
  is enabled.

- Remove `ergoemacs-this-command' count from `keyfreq-table' when
  `keyfreq-mode' is enabled.

- set `this-command' to the function called.

"
  (setq ergoemacs-deactivate-mark nil)
  (when (and ergoemacs-read-key-last-help (boundp 'guide-key-mode) guide-key-mode)
    (setq ergoemacs-read-key-last-help nil)
    (guide-key/close-guide-buffer))
  (cond
   ((ergoemacs-smart-function-p function)
    (error "Ergoemacs-mode is confused, and exiting out of an infinite loop (refused to call %s)" function))
   (ergoemacs-test-fn
    (setq ergoemacs-test-fn function))
   (ergoemacs-describe-key
    (let ((pt (point))
          (buf (current-buffer))
          (keys '())
          test)
      (unwind-protect
          (save-excursion
            (describe-function function)
            (set-buffer (help-buffer))
            (let ((inhibit-read-only t))
              (goto-char (point-min))
              (insert (format "%s runs the command "
                              (ergoemacs-pretty-key (key-description keys))))
              (when (search-forward " is" nil t)
                (replace-match ", which is"))
              (fill-paragraph)
              (when (search-forward "bound to" nil t)
                (delete-region
                 (point)
                 (if (re-search-forward "\\.\n\n") (point) (point)))
                (with-current-buffer buf
                  (goto-char pt)
                  (ergoemacs-with-global
                   (dolist (global-key (where-is-internal function))
                     (setq test (gethash global-key ergoemacs-original-keys-to-shortcut-keys))
                     (when test
                       (dolist (global-key test)
                         (unless (eq (elt global-key 0) 'menu-bar)
                           (push (ergoemacs-pretty-key (key-description global-key))
                                 keys))))))
                  (let (ergoemacs-modal ergoemacs-repeat-keys ergoemacs-read-input-keys
                                        ergoemacs-shortcut-keys ergoemacs-no-shortcut-keys)
                    (dolist (global-key (where-is-internal function))
                      (unless (eq (elt global-key 0) 'menu-bar)
                        (push (ergoemacs-pretty-key (key-description global-key))
                            keys)))))
                (insert (mapconcat (lambda(x) x) keys ", "))
                (insert ".\n\n"))))
        (setq ergoemacs-describe-key nil))))
   ((ignore-errors (string-match "self-insert" (symbol-name function)))
    (setq ergoemacs-single-command-keys keys)
    (setq last-input-event keys)
    (setq prefix-arg current-prefix-arg)
    (setq unread-command-events (append (listify-key-sequence keys) unread-command-events))
    (ergoemacs-defer-post-command-hook)
    (reset-this-command-lengths))
   (t
    (dolist (var ergoemacs-this-command-fake)
      ;; should include `this-command' and `this-original-command'
      (set var function))
    (let ((this-command-keys-shift-translated
           (or this-command-keys-shift-translated
               (if ergoemacs-shift-translated t nil))))
      ;; Try to maintain shift-selection.
      (when (and ergoemacs-shift-translated
                 (ergoemacs-is-movement-command-p function))
        (cond
         ((and shift-select-mode ergoemacs-force-shift-select-mark-active
               (not mark-active))
          ;; Mark was active, then it was deactivated, now activate again.
          (unless (and mark-active
                       (eq (car-safe transient-mark-mode) 'only))
            (setq transient-mark-mode
                  (cons 'only
                        (unless (eq transient-mark-mode 'lambda)
                          transient-mark-mode))
                  mark-active t)))
         (t ;; Mark was not active, activate mark.
          (handle-shift-selection))))
      (when (featurep 'keyfreq)
        (when keyfreq-mode
          (let ((command ergoemacs-this-command) count)
            (setq count (gethash (cons major-mode command) keyfreq-table))
            (cond
             ((not count))
             ((= count 1)
              (remhash (cons major-mode command) keyfreq-table))
             (count
              (puthash (cons major-mode command) (- count 1)
                       keyfreq-table)))
            ;; Add local-fn to counter.
            (setq count (gethash (cons major-mode function) keyfreq-table))
            (puthash (cons major-mode function) (if count (+ count 1) 1)
                     keyfreq-table))))
      (let (deactivate-mark
            (ergoemacs-single-command-keys keys))
    (remove-hook 'ergoemacs-pre-command-hook 'ergoemacs-pre-command-hook)
    (remove-hook 'ergoemacs-pre-command-hook 'ergoemacs-pre-command-hook t)
        (run-hooks 'ergoemacs-pre-command-hook)
        (call-interactively this-command record-flag keys)
        (setq ergoemacs-deactivate-mark deactivate-mark)
        (when deactivate-mark
          (setq ergoemacs-mark-active nil))))))
  (when ergoemacs-deactivate-mark
    (setq deactivate-mark ergoemacs-deactivate-mark
          ergoemacs-mark-active nil)
    (setq ergoemacs-deactivate-mark nil)))
(ergoemacs-mode 1)
mattfidler commented 9 years ago

In your bug you were wondering what was changed and possibly why. Your hypothesis was that it was regular expression matching. FYI: I don't actually change anything in regular expression matching.

Here is what I change and why:

In prior bugs with multiple-cursors this is where the incompatibility lies.

The other thing that is modified is generalized keymaps. Things like org-mode try to be smart and overwrite keys like C-x C-s with their own version of save-buffer in things like org-agenda-mode. ergoemacs-mode attempts to detect such modifications and put them on the correct ergoemacs-mode keys (in this case Control-s)

liefswanson commented 9 years ago

wow! thanks for the well done response...

I will try this out as soon as i have a chance, which may not be for a day or two.

liefswanson commented 9 years ago

I found the issue... but it honestly has be a bit perplexed. (granted, i have little knowledge of either code-base).

When you said you could not reproduce I went through all the possible things that would differ in our systems and found the offender quickly. my keyboard is set to programmers-dvorak, and I have bound the the mc/mark-next-like-this and mc/mark-previous-like-this to C-n and C-h respectively.

IE: they are conflicting with one of the bindings in the ergoemacs-map(s). in qwerty those bindings would be C-l and C-j respectively.

When I found this I thought it may be a collision of my global bindings with your bindings in the ergoemacs-map(s). However, no matter what I change them to I get the same behaviour. This does not appear to happen in workman. qwerty, swedish. (I did not try every variant just those three.)

It also occurs in the other dvoraks. but i am having trouble making it happen consistently. It may have something to do with the method i use to highlight typically i use the M-space combo to set M-n to highlight word then C-n to highlight next. I of course cannot use that combo without remembering where they map to in the otherlayouts and i actually highlighted them with the mouse or arrow keys.

It should be noted that I kept my keyboard as programmers-dvorak at desktop environment level while changing around the ergoemacs maps.

Additionally that function did not change this issue. Still works with the other layouts, but not in programmers-dvorak

I am going to quickly update my .emacs.d repo , if it helps you... It should in theory be able to just be cloned into an empty .emacs.d and then have emacs start up and auto grab my package-list with my settings etc.

Sorry about not trying that before filing a bug, It did not seem relevant until you said that you could not reproduce

liefswanson commented 9 years ago

I will try and clarify anything i can later, but i really have been procrastinating something to figure all that out, I will try and get back to you when i can.

mattfidler commented 9 years ago

You can try to enclose the bindings in an ergoemacs mode theme component to see if this works.

I don't have access to a computer currently so I will try to put code out there that I cannot verify...

(ergoemacs-component my-mc () 
"My mc"
(global-set-key (kbd "C-n") 'mc/mark-next-like-this)
(global-set-key (kbd "C-h") 'mc/mark-previous-like-this)) 

(ergoemacs-require 'my-mc) 
mattfidler commented 9 years ago

I won't be able to do anything really until next week.

mattfidler commented 9 years ago

It seems to be working for me again, with a new engine. I'm unsure if it will work for you. I'm trying to create tests and they don't seem to work well, though they run in my true interactive session correctly.