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:

# MULTILINE!!!
bindkey '^[e' push-line-or-edit

# enter accepts when only one line found, else creates newline
function _zle_ml_enter {
    if ! [[ $BUFFER == *$'\n'* ]]; 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 [[ $BUFFER == *$'\n'* ]]; then
        zle accept-line
    else
        zle self-insert-unmeta
    fi
}
zle -N _zle_ml_meta_enter
bindkey '^[^M' _zle_ml_meta_enter

edit:
changed if [[ "$BUFFERLINES" -le 1 ]]; then to if ! [[ $BUFFER == *$'\n'* ]]; then and if [[ "$BUFFERLINES" -gt 1 ]]; then to if [[ $BUFFER == *$'\n'* ]]; then for improving detection. Also added alt-e shortcut because I had that configured myself but forgot to add here.

  • Andy
    link
    fedilink
    English
    arrow-up
    1
    ·
    1 day ago

    It’s been a while, but my clumsy adding of a comment to the buffer is unnecessary, given zle -M, which will display a message outside of the buffer. So here’s an updated version:

    # -- Run input if single line, otherwise insert newline --
    # Key: enter
    # Credit: https://programming.dev/comment/2479198
    .zle_accept-except-multiline () {
      if [[ $BUFFER != *$'\n'* ]] {
        zle .accept-line
        return
      } else {
        zle .self-insert-unmeta
        zle -M 'Use alt+enter to submit this multiline input'
      }
    }
    zle -N       .zle_accept-except-multiline
    bindkey '^M' .zle_accept-except-multiline  # Enter
    
    # -- Run input if multiline, otherwise insert newline --
    # Key: alt+enter
    # Credit: https://programming.dev/comment/2479198
    .zle_accept-only-multiline () {
      if [[ $BUFFER == *$'\n'* ]] {
        zle .accept-line
      } else {
        zle .self-insert-unmeta
      }
    }
    zle -N         .zle_accept-only-multiline
    bindkey '^[^M' .zle_accept-only-multiline  # Enter