Silently edit a buffer

26 views
Skip to first unread message

Dmitry Zotikov

unread,
Aug 15, 2017, 5:58:33 PM8/15/17
to v...@vim.org
Dear all,
 
what would be the best way to silently edit a buffer? In particular, I want to
be able to write the content of a variable to it, as well as to delete all of
its content.
 
The story goes, I'm writing a plugin that among other things reads from a
network socket using Vim 8 channels and jobs; this is the corresponding call:
 
call job_start(command_cmd, {'out_io': 'buffer', 'out_name': '_out'})
 
The problem is that on the other side of the socket there's a server process
which doesn't append a newline after it finishes its write. Consequently,
reading from the channel set to NL mode would always leave one line of input in
the socket, and so I'm forced to either fall back to RAW mode, or to check
whether there's something left in the socket and read it later with a separate
ch_read call:
 
- Writing in RAW mode directly to the buffer leaves ^@ in place of proper
linefeeds, meaning a callback function would have to be called, that would
substitute ^@ with ^M and only then write to the buffer; this is where the
initial question stems from.
- ch_read() call would also have to be performed by a callback function that
will, again, need a way to somehow write to the buffer.
 
The closest solution I've got is to do something like
 
:bufnr('_out') bufdo put =msg
 
but that switches the current window to "_out" buffer.
 
--
Regards,
Dmitry
 

Nikolay Aleksandrovich Pavlov

unread,
Aug 15, 2017, 7:07:22 PM8/15/17
to vim...@googlegroups.com, vim
2017-08-15 21:56 GMT+03:00 Dmitry Zotikov <x...@ungrund.org>:
> Dear all,
>
> what would be the best way to silently edit a buffer? In particular, I want
> to
> be able to write the content of a variable to it, as well as to delete all
> of
> its content.
>
> The story goes, I'm writing a plugin that among other things reads from a
> network socket using Vim 8 channels and jobs; this is the corresponding
> call:
>
> call job_start(command_cmd, {'out_io': 'buffer', 'out_name': '_out'})
>
> The problem is that on the other side of the socket there's a server process
> which doesn't append a newline after it finishes its write. Consequently,
> reading from the channel set to NL mode would always leave one line of input
> in
> the socket, and so I'm forced to either fall back to RAW mode, or to check
> whether there's something left in the socket and read it later with a
> separate
> ch_read call:
>
> - Writing in RAW mode directly to the buffer leaves ^@ in place of proper
> linefeeds, meaning a callback function would have to be called, that would
> substitute ^@ with ^M and only then write to the buffer; this is where the
> initial question stems from.

I would say that what you see looks like a bug: ^@ is LF (also known
as NL or "\n", byte 0xA), but in a buffer LF is used to represent NUL
and this is why it appears as ^@ (see `:h NL-used-for-Nul`). So if you
have a server which outputs LF separators and buffer is opened with
`unix` `&fileformat` appearing ^@ should be a bug. Though if the
server actually outputs NUL bytes it is not a bug.

Note that ^M or CR or `\r` or byte 0xD is *not* a line feed. Just
`:put` converts *both* CR and LF to a newline, so you probably don’t
need to do any substitutions.

(And note that newline in a buffer is neither CR nor LF. It is “NUL”
which terminates a C string which represents a buffer line, conversion
to CR, LF or CRLF is done on write according to `&fileformat` option.)

> - ch_read() call would also have to be performed by a callback function that
> will, again, need a way to somehow write to the buffer.
>
> The closest solution I've got is to do something like
>
> :bufnr('_out') bufdo put =msg
>
> but that switches the current window to "_out" buffer.

You may try using Python `vim.Buffer` class, I am not aware of
anything else which may do update without switching buffers
explicitly. Or just write in a scratch tab page, with all commands to
create it protected by &eventignore='all' and &lazyredraw=1, scratch
tab is to be destroyed after writing. Or create a wrapper script which
will add a newline at the end and which should be communicated with in
place of the server directly.

>
> --
> Regards,
> Dmitry
>
>
> --
> --
> You received this message from the "vim_use" maillist.
> Do not top-post! Type your reply below the text you are replying to.
> For more information, visit http://www.vim.org/maillist.php
>
> ---
> You received this message because you are subscribed to the Google Groups
> "vim_use" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to vim_use+u...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Bram Moolenaar

unread,
Aug 16, 2017, 4:46:32 PM8/16/17
to vim...@googlegroups.com, Dmitry Zotikov

Dmitry Zotikov wrote:

> Dear all,
>  
> what would be the best way to silently edit a buffer? In particular, I want to
> be able to write the content of a variable to it, as well as to delete all of
> its content.
>  
> The story goes, I'm writing a plugin that among other things reads from a
> network socket using Vim 8 channels and jobs; this is the corresponding call:
>  
> call job_start(command_cmd, {'out_io': 'buffer', 'out_name': '_out'})
>  
> The problem is that on the other side of the socket there's a server process
> reading from the channel set to NL mode would always leave one line of
> input in the socket, and so I'm forced to either fall back to RAW
> mode, or to check whether there's something left in the socket and
> read it later with a separate ch_read call:

I created a file "temp" that is missing the final EOL.
If I then do:
call job_start("cat temp", {'out_io': 'buffer', 'out_name': '_out'})
Then I see the last line of "temp" in _out.
Thus it appears to work.
Perhaps the server process doesn't flush the output?

> - Writing in RAW mode directly to the buffer leaves ^@ in place of proper
> linefeeds, meaning a callback function would have to be called, that would
> substitute ^@ with ^M and only then write to the buffer; this is where the
> initial question stems from.
> - ch_read() call would also have to be performed by a callback function that
> will, again, need a way to somehow write to the buffer.
>  
> The closest solution I've got is to do something like
>  
> :bufnr('_out') bufdo put =msg
>  
> but that switches the current window to "_out" buffer.

--
There are two ways of constructing a software design. One way is to make
it so simple that there are obviously no deficiencies. The other way
is to make it so complicated that there are no obvious deficiencies.
-C.A.R. Hoare

/// Bram Moolenaar -- Br...@Moolenaar.net -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///

Dmitry Zotikov

unread,
Aug 16, 2017, 4:50:51 PM8/16/17
to Bram Moolenaar, vim...@googlegroups.com
16.08.2017, 23:46, "Bram Moolenaar" <br...@moolenaar.net>:
> Dmitry Zotikov wrote:
>
>>  Dear all,
>>
>>  what would be the best way to silently edit a buffer? In particular, I want to
>>  be able to write the content of a variable to it, as well as to delete all of
>>  its content.
>>
>>  The story goes, I'm writing a plugin that among other things reads from a
>>  network socket using Vim 8 channels and jobs; this is the corresponding call:
>>
>>  call job_start(command_cmd, {'out_io': 'buffer', 'out_name': '_out'})
>>
>>  The problem is that on the other side of the socket there's a server process
>>  reading from the channel set to NL mode would always leave one line of
>>  input in the socket, and so I'm forced to either fall back to RAW
>>  mode, or to check whether there's something left in the socket and
>>  read it later with a separate ch_read call:
>
> I created a file "temp" that is missing the final EOL.
> If I then do:
>          call job_start("cat temp", {'out_io': 'buffer', 'out_name': '_out'})
> Then I see the last line of "temp" in _out.
> Thus it appears to work.
> Perhaps the server process doesn't flush the output?

Yes, most likely. Seems like there's nothing I could do about it (the process is
SAS interpreter).

himzoidae

unread,
Aug 16, 2017, 5:05:37 PM8/16/17
to vim_use, v...@vim.org
Thank you for your quick reply.

Perhaps it is indeed a bug, just wrote to vim-dev.

>
> > - ch_read() call would also have to be performed by a callback function that
> > will, again, need a way to somehow write to the buffer.
> >
> > The closest solution I've got is to do something like
> >
> > :bufnr('_out') bufdo put =msg
> >
> > but that switches the current window to "_out" buffer.
>
> You may try using Python `vim.Buffer` class, I am not aware of
> anything else which may do update without switching buffers
> explicitly. Or just write in a scratch tab page, with all commands to
> create it protected by &eventignore='all' and &lazyredraw=1, scratch
> tab is to be destroyed after writing. Or create a wrapper script which
> will add a newline at the end and which should be communicated with in
> place of the server directly.

Ah, using a scratch tab works great, thanks.

Writing a wrapper script would involve some sort of "waiting for a while to make
sure the process has finished writing" logic, which I avoid for aesthetic
reasons :)

--
Dmitry
Reply all
Reply to author
Forward
0 new messages