I’m an Emacs newbie (using Doom Emacs with GNU Emacs 29.1). I came from vim, and battling with undo there was crazy enough, but I won using this:

inoremap  u
inoremap  u
inoremap  u
inoremap  u
inoremap  u
inoremap  u
inoremap  u
inoremap , ,u
inoremap . .u
inoremap ( (u
inoremap [ [u
inoremap = =u
inoremap \" \"u
inoremap  u
inoremap  u

Also, I had autogroup that breaks undo every 4 seconds.

Basically, this configuration breaks undo on almost every possible type command, every Spacebar, Enter, comma, bracket, moving up, down, everything. This is because I hate when undo deletes the whole screen of text.

How do I replicate this in Emacs? I read this, but it doesn’t say what is considered a “recent change”.

  • 7890yuiop@fediverser.communick.devB
    link
    fedilink
    English
    arrow-up
    1
    ·
    1 year ago

    What does “break undo” mean? Do you mean that if you type “x” and then you type “y” and then you use undo, the first undo should remove only the “y” and the second would remove the “x”?

      • juboba@fediverser.communick.devB
        link
        fedilink
        English
        arrow-up
        1
        ·
        1 year ago

        I think you are not used to ‘modal’ editing in Vi. How does the world use it? With atomic edits, which means living in NORMAL mode and only entering INSERT mode when you need it. Your undo history works like a commit history and you can undo by action: inserted text, changed text inside brackets, deleted 6 lines, etc. If you get used to this, you’ll never go back (even in Emacs, Evil user here hehe).

        • chesheersmile@fediverser.communick.devOPB
          link
          fedilink
          English
          arrow-up
          1
          ·
          1 year ago

          This way of modal editing is fine when you write source code.

          I write texts, articles. Most of the time I spend in Insert mode. And when I press u I see a wall of text disappeared.

          • thetemp_@fediverser.communick.devB
            link
            fedilink
            English
            arrow-up
            1
            ·
            1 year ago

            And when I press u I see a wall of text disappeared.

            Maybe Vim let’s things go too far between undos.

            I write a lot of text too, but I’ve never seen Emacs’s undo remove a whole wall of text that was typed by hand. If it was inserted from the kill-ring, sure.

            Occasionally, it’ll undo a few more keystrokes than I’d prefer, but that’s rare. In that case, you can just undo the undo by pressing “C-g C-/”. And then remove only the text you wanted to get rid of.

            • oantolin@fediverser.communick.devB
              link
              fedilink
              English
              arrow-up
              1
              ·
              1 year ago

              Maybe Vim let’s things go too far between undos?

              By default Vim makes each foray into insert mode undo in a single step. So you have total control over how much gets undone each time: just exit and renter insert mode if you want more granular undo.

      • 7890yuiop@fediverser.communick.devB
        link
        fedilink
        English
        arrow-up
        1
        ·
        1 year ago

        I think /u/bravosierrasierra has your solution with amalgamating-undo-limit then. Except the docstring may have an off-by-one error: experimentally it seems as if you need (setq amalgamating-undo-limit 0) rather than the indicated value of 1.

  • FrozenOnPluto@fediverser.communick.devB
    link
    fedilink
    English
    arrow-up
    1
    ·
    1 year ago

    Emacs is king of undo. Theres a number of ways but you can bsck up the undo chain a step or steps at a time. Ie if you’ve done 20 changes you can just keep going back with a keystroke.

    There is also undo-tree package so you can visually see what state your buffer has been in over time and then just go pick the state you want.

    • SnooPets20@fediverser.communick.devB
      link
      fedilink
      English
      arrow-up
      1
      ·
      1 year ago

      Do note that undo-tree not only provides a visual, it is a fundamentally different way of doing undos. The stock emacs way is not a tree, it’s a line. There’s no real “redo” in emacs for instance, you just undo an undo. It’s odd, but undo tree works really well.

  • orzechod@fediverser.communick.devB
    link
    fedilink
    English
    arrow-up
    1
    ·
    1 year ago

    the paragraph here gives some useful details: https://www.gnu.org/software/emacs/manual/html_node/elisp/Undo.html#index-undo_002dauto_002damalgamate

    The editor command loop automatically calls undo-boundary just before executing each key sequence, so that each undo normally undoes the effects of one command. A few exceptional commands are amalgamating: these commands generally cause small changes to buffers, so with these a boundary is inserted only every 20th command, allowing the changes to be undone as a group. By default, the commands self-insert-command, which produces self-inserting input characters (see User-Level Insertion Commands), and delete-char, which deletes characters (see Deleting Text), are amalgamating.

    this means emacs will group together a certain number of inserted characters into an atomic unit; it’s that unit which is undone by the undo command. if you want character-by-character undo then you will need to tell emacs to not perform this grouping. one thing to try would be to add advice to the insert-char function to set that undo boundary for you upon each keystroke; I’m sure there are other ways to do this as well.

    • Gandalf_the_Gray@fediverser.communick.devB
      link
      fedilink
      English
      arrow-up
      1
      ·
      1 year ago

      The following paragraph from what you quote has the heavy handed approach whereby no changes are amalgamated and undo would work character by character.

      The maximum number of changes that can be amalgamated is controlled by the amalgamating-undo-limit variable. If this variable is 1, no changes are amalgamated.

  • bmax64@fediverser.communick.devB
    link
    fedilink
    English
    arrow-up
    1
    ·
    1 year ago

    paste this in chat gpt and go from there?

    I used to have these vim bindings in vim
    how do i write emacs lisp to do this same stuff in evil-mode
    inoremap  u
    inoremap  u
    inoremap  u
    inoremap  u
    inoremap  u
    inoremap  u
    inoremap  u
    inoremap , ,u
    inoremap . .u
    inoremap ( (u
    inoremap [ [u
    inoremap = =u
    inoremap \" \"u
    inoremap  u
    inoremap  u
    

    I got something like this:

    https://preview.redd.it/kvnebrhls6vb1.png?width=853&format=png&auto=webp&s=344cc711cb301117cd9ed8dbf06791f97004c33d

      • db48x@fediverser.communick.devB
        link
        fedilink
        English
        arrow-up
        1
        ·
        1 year ago

        Good, because that is very bad advice. orzechod already gave you a link to the manual, but the upshot is that basically every emacs command already breaks the undo into segments. Arrow keys invoke commands to move the cursor around, and backspace and return invoke commands as well, so you don’t need to add anything to your config to get most of what you want.

        The only difference is that the default Emacs config groups up inserted characters into segments of 20 characters, instead of splitting them on punctuation and spaces. Getting that last bit is harder, so you might actually prefer to live with it. You should be able to do it with advice on self-insert-command, but I would have to do a little research and try it out before I would be confident in my answer. (I am 90% sure that you can set a variable to control whether the current command should be amalgamated or not, but it’s been years since I last looked at how undo is implemented.)

        I should also point out that brackets might or might not be amalgamated depending on other choices you might have made. For example, if you use a minor mode that automatically inserts the closing bracket when you type the opener, then it won’t be amalgamated because that is invoking a command rather than merely inserting a character.

        • chesheersmile@fediverser.communick.devOPB
          link
          fedilink
          English
          arrow-up
          1
          ·
          1 year ago

          Advising self-insert-command may be a way. But with my zero knowledge of elisp I have absolutely no idea how to do that. All my attempts have failed.

          So for now this kinda adds to my long list of “Not solved in any reasonable way”.