Some time ago I found xonsh which is a python-based shell. It had really good multiline support, and I am searching for a shell with sameish multiline support as xonsh. Fish shell also has good multiline support, it is around the same level, but it is not posix compatible. I want a shell that has that kind of level of multiline, but zsh (bash is also fine) compatible.

Does anyone know of one?

edit: based on the replies, I get this is unclear. My problem with zsh is that if i press enter and it starts a new line, I can’t get back to the prevous line, because a new prompt is started. In fish this is possible, all lines are one prompt. But, fish is not posix compatible. So, I guess I want a posix-compatible shell with fish-like lines (multiple line) editing. I wanted zsh support to keep using my custom oh-my-zsh prompt, but remaking it for a new shell is not a big problem. Sorry for being unclear.

edit 2: solution is here! Thanks to @[email protected] I started thinking and made the following: When on the first line, enter accepts and alt-enter inserts a newline. When not on the first line, enter inserts a newline and alt-enter accepts. Here is the code to put in your .zshrc:


# enter accepts when only one line found, else creates newline
function _zle_ml_enter {
    if [[ "$BUFFERLINES" -le 1 ]]; then
        zle accept-line
    else
        zle self-insert-unmeta
    fi
}
zle -N _zle_ml_enter
bindkey '^M' _zle_ml_enter

# alt-enter accepts when more than one line found, else creates newline
function _zle_ml_meta_enter {
    if [[ "$BUFFERLINES" -gt 1 ]]; then
        zle accept-line
    else
        zle self-insert-unmeta
    fi
}
zle -N _zle_ml_meta_enter
bindkey '^[^M' _zle_ml_meta_enter

  • Andy@programming.dev
    link
    fedilink
    arrow-up
    1
    ·
    edit-2
    1 year ago

    OK, well FWIW in Zsh you can use a keybind to trigger ZLE functions that turn your already-entered lines back into in-progress lines.

    The most straightforward built-in function for this is push-line-or-edit:

    At the top-level (PS1) prompt, equivalent to push-line. At a secondary (PS2) prompt, move the entire current multiline construct into the editor buffer. The latter is equivalent to push-input followed by get-line.

    So let’s say you want to trigger this with ctrl+e, all you need is:

    bindkey '^e' push-line-or-edit
    
    • vosjedev@lemm.eeOP
      link
      fedilink
      arrow-up
      1
      ·
      1 year ago

      Thanks for your reply! This made me think: could I bind enter to newline and alt-enter to accept, which then made me think if it was possible to have enter to accept and alt-enter to newline on first line only, after that in reverse. That made me think of the script I added to the post.

      But serious, without this I would have never thought of doing what I did.

      • Andy@programming.dev
        link
        fedilink
        arrow-up
        1
        ·
        edit-2
        1 year ago

        I started using this, it makes a lot of sense and I like it, thanks!

        I can imagine myself forgetting how to accept multiline input with alt+enter, so I added a help message to _zle_ml_enter in the multiline case after the second line. It assumes setopt interactivecomments is already set:

        EDIT: note that lemmy mangles the less-than symbol

        # -- Run input if single line, otherwise insert newline --
        # Key: enter
        # Assumes: setopt interactivecomments
        # Credit: https://programming.dev/comment/2479198
        .zle_accept-except-multiline () {
          if (( BUFFERLINES <= 1 )) {
            zle accept-line
          } else {
            zle self-insert-unmeta
            if (( BUFFERLINES == 2 )) {
              LBUFFER+="# Use alt+enter to submit this multiline input"
              zle self-insert-unmeta
            }
          }
        }
        zle -N .zle_accept-except-multiline
        bindkey '^M' .zle_accept-except-multiline  # Enter