equalsraf / neovim-qt

Neovim client library and GUI, in Qt5.
https://github.com/equalsraf/neovim-qt/wiki
ISC License
1.85k stars 171 forks source link

Open input from stdin #275

Open SevereOverfl0w opened 7 years ago

SevereOverfl0w commented 7 years ago

echo hi | nvim - opens hi in nvim buffer.

echo hi | nvim-qt - errors. Also echo hi | nvim-qt --nofork - errors. Error with nofork is:

QSocketNotifier: Invalid socket 9 and type 'Write', disabling...
Request 2 timed out: 76
Neovim fatal error "Neovim is taking too long to respond"

I think nvim-qt needs to pass through stdin to nvim.

equalsraf commented 7 years ago

The problem here is that (for the default case) nvim's stdin is already in use, because nvim-qt starts nvim as nvim --embed, the --embed option uses stdin/stdout as an rpc channel between nvim and nvim-qt.

So simply passing the stdin is not an option, unless we somehow change the startup sequence (like https://github.com/equalsraf/neovim-qt/issues/50 suggests) e.g. it is possible to write a vimscript to start the gui

" start-nvim-qt.vim
let job = rpcstart('./nvim-qt', ['--embed', '--nofork'])

and then, this should work

echo hello | nvim --cmd "source start-nvim-qt.vim" --headless -

Bear in mind that this example is lacking in that it does not ensure the GUI shim is loaded and so GuiFont/ginit.vim and other features will not work properly as is.

facundobatista commented 4 years ago

Have been considered the case of having other sockets to RPC on?

Like, starting (for example nvim --embed --rpc-sockets=foo,bar, and then communicate with nvim through those sockets, not stdin/stdout.

Of course, nvim would need to grow support for this, but it shouldn't be too hard (at least in POSIX systems).

Thanks!

justinmk commented 4 years ago

@facundobatista Nvim already supports that, so I don't understand the question?

facundobatista commented 4 years ago

@justinmk hola! So you say that nvim already supports RPC on different channels than stdin/stdout? If that's the case, we only need to improve neovim-qt to use other channels, leaving stdin free?

justinmk commented 4 years ago
:help serverstart()
facundobatista commented 4 years ago

@equalsraf is it possible to make nvim-qt to use other socket, as @justinmk is indicating, so we release stdin to be used as text input for the buffer?

equalsraf commented 4 years ago

@equalsraf is it possible to make nvim-qt to use other socket

Probably not anymore. Some things changed since this issue was opened.

nvim is called by nvim-qt using the --embed flag which changes how neovim starts up - in particular it delays startup until the ui connects to avoid other issues. If we switched to using a different socket and allowing nvim to take in stdin input directly then the --embed behaviour would no longer be used (which would bring back past issues about error handling and startup). Right now I dont think this can be resolved this way and i dont think that is the main issue.

There is also another problem here in how exactly stdin would be passed to nvim (lets ignore the fork problem for now)

echo hi | nvim-qt -
# nvim-qt calls nvim, which means stdin needs to passed to the child
# if **-** is one of the file arguments.

what i suggested earlier was to simply invert this. Calling nvim (where test.vim starts nvim-qt via vimscript)

dmesg | nvim --cmd "source test.vim" --headless -

In either of these cases there are side effects

I am leaning away from any of the proposed solutions so far. Worst case scenario nvim-qt will have to handle stdin reading before starting up nvim and find a way to load it into a buffer - i'm not sure what is the best way to do this though.

facundobatista commented 4 years ago

Worst case scenario nvim-qt will have to handle stdin reading before starting up nvim and find a way to load it into a buffer - i'm not sure what is the best way to do this though.

Read from stdlin and write into a temp file? Not everything at once, of course, chunk by chunk. Shouldn't be too hard.

And then tell nvim to open that temp file, of course.

equalsraf commented 4 years ago

And then tell nvim to open that temp file, of course.

This last bit is more like load all data into an empty buffer. Otherwise nvim will open the file which is not what you want.

facundobatista commented 4 years ago

Yes, probably, this is too subtle for me.

I was just doing some tests with gVim: head -c 1223 /dev/urandom | gvim - ... when I do that, it creates an empty temp directory (e.g. /tmp/vuSVP4h), I'm not sure what for.

Also checking what file descriptors has the process...

23:36:52|facundo@blackfx:/proc/15351$ ll fd
total 0
lrwx------ 1 facundo facundo 64 feb 20 23:36 0 -> /dev/pts/13
lrwx------ 1 facundo facundo 64 feb 20 23:36 1 -> /dev/pts/13
lrwx------ 1 facundo facundo 64 feb 20 23:36 10 -> socket:[20391476]
lrwx------ 1 facundo facundo 64 feb 20 23:36 11 -> anon_inode:[eventfd]
lrwx------ 1 facundo facundo 64 feb 20 23:36 2 -> /dev/pts/13
lrwx------ 1 facundo facundo 64 feb 20 23:36 20 -> socket:[2482947]
lrwx------ 1 facundo facundo 64 feb 20 23:36 3 -> socket:[20399638]
lrwx------ 1 facundo facundo 64 feb 20 23:36 4 -> anon_inode:[eventfd]
lrwx------ 1 facundo facundo 64 feb 20 23:36 5 -> /home/facundo/.svz
lrwx------ 1 facundo facundo 64 feb 20 23:36 6 -> socket:[20400350]
lrwx------ 1 facundo facundo 64 feb 20 23:36 7 -> anon_inode:[eventfd]
lrwx------ 1 facundo facundo 64 feb 20 23:36 8 -> socket:[20397377]
lrwx------ 1 facundo facundo 64 feb 20 23:36 9 -> anon_inode:[eventfd]

I found that temp buffer one:

23:37:16|facundo@blackfx:~$ stat .svz
  Fichero: .svz
  Tamaño: 12288         Bloques: 24         Bloque E/S: 4096   fichero regular
Dispositivo: 803h/2051d Nodo-i: 70214387    Enlaces: 1
Acceso: (0600/-rw-------)  Uid: ( 1000/ facundo)   Gid: ( 1000/ facundo)
Acceso: 2020-02-20 23:36:13.129432736 -0300
Modificación: 2020-02-20 23:36:22.217320163 -0300
      Cambio: 2020-02-20 23:36:22.217320163 -0300
    Creación: -

But I don't really understand what's going on here...

cvmocanu commented 2 years ago

This issue has been a major hurdle for me, coming from gvim (which is able to read stdin just fine). I have multiple things that depend on this:

Please fix this.

In the mean time, there is a workaround, at least on Linux. The idea is this: if nvim-qt cannot read from stdin/pipes, and can read from files, why not give it a file, which is a pipe - a named pipe?

Create an nv- file (make it executable & put in your $PATH), with the following content:

#!/usr/bin/env bash

function mk_tmp_fifo() {
    local temp_path
    temp_path="$(mktemp --dry-run)"
    local temp_full_path
    temp_full_path="$(readlink -f "${temp_path}")"

    mkfifo --mode=600 "${temp_full_path}"

    printf '%s' "${temp_full_path}"
}

function nv_from_stdin() {
    local nvim_pipe
    nvim_pipe="$(mk_tmp_fifo)"

    local cleanup_wait_pipe
    cleanup_wait_pipe="$(mk_tmp_fifo)"

    (
        nvim-qt \
            --spawn \
            -- \
            nvim \
                --cmd "let old_undolevels = &undolevels" \
                --cmd "set undolevels=-1" \
                --cmd "0read ${nvim_pipe}" \
                --cmd "let &undolevels = old_undolevels" \
                --cmd "unlet old_undolevels" \
                --cmd 'set nomodified' \
                "${@}"

        # signal cleanup process that it's ok to start cleaning up
        printf '' > "${cleanup_wait_pipe}"
    )&

    # pass stdin to the nvim_pipe
    cat /dev/stdin > "${nvim_pipe}"

    (
        cat "${cleanup_wait_pipe}" # wait for nvim to read the stdin

        rm "${nvim_pipe}"
        rm "${cleanup_wait_pipe}"
    )&
}

nv_from_stdin "${@}"

You can use it like this:

</path/to/my/file nv-

Or like this:

echo '<root></root>' | nv- --cmd 'set ft=xml'
cvmocanu commented 2 years ago

To use this as a PAGER, add export PAGER='/path/to/nv-' to your shell's startup file.

Unfortunately this can't be used as a pager for man, since neovim displays unescaped BACKSPACE (^H) characters.

To fix this, create a nv-manpager file (make it executable), with the following content:

#!/usr/bin/env bash

col -bx | NO_AT_BRIDGE=1 /home/cvmocanu/Dropbox/Configuration/bin/nv- --cmd "set ft=man"

To explain the script:

Then add this to your shell startup script: export MANPAGER='/path/to/nv-manpager'.

cvmocanu commented 2 years ago

Improving the above shell script by people more knowledgeable with bash than me is appreciated.

hrw commented 10 months ago

Is there any Neovim GUI variants which supports stdin without external scripts?