Re: adding additional network stuff in RealWaitForChar?

2006-09-12 Thread Brad Beveridge

On 11/09/06, Gaspar Chilingarov [EMAIL PROTECTED] wrote:

Hello all vimmers!

I would like to ask - how should I add additional stuff in
RealWaitForChar? I have some network protocol, when another side
periodically send me keepalive messages(every 10-15 secs). I would like
to receive them and process. In GUI based vim it was pretty simple --
using gdk_input_add or similar thing. In other hand I would like to
console users have same benefits - I've added handlers in
RealWaitForChar, but ... it processes only first message on it's own.
All latter messages are  received, but does not processed -- until I
press some key periodically, thus causing remote site timeouting and
aborting the connection.

I've implemented it in a quite similar way to FEAT_MOUSE_GPM and
USE_XSMP implementations.

What can I miss there? Any recommendations where to look?

Thanks in advance, Gaspar


There is a patched Vim7 here
(http://theclapp.org/repos/vim70+async+ecl/) that contains code to
handle network callbacks.  However, beware!  I think there are subtle
bugs in way this works with Vim's code path.  You cannot just randomly
go calling functions from RealWaitForChar (for example, appending
text), and expect everything to be OK.  You probably want to look in
network_io.c and os_unix.c.

Cheers
Brad


Re: Fastest way to append line or char to a buffer

2006-08-29 Thread Brad Beveridge

On 29/08/06, Ilya [EMAIL PROTECTED] wrote:

Brad Beveridge wrote:
 On 26/08/06, Brad Beveridge [EMAIL PROTECTED] wrote:
 SNIP

 Cheers
 Brad

 Hi, sorry for all the trouble :)  I'm having redraw issues, where
 running this code to append chars is causing strange problems.
 The scenario is this (always using the code below for char output):
 1) Write a char to a buffer (line1)
 2) Write a newline (line 2)
 3) Move the cursor to the bottom of the buffer (line2 empty)
 4) Write another Char (appears in line2)
 5) Press Ctrl-L
 6) Notice that line1 has vanished.

 moving the cursor to the new blank line at the bottom of the line is
 critical here.  I'm sure that I'm doing something wrong, but I really
 can't figure it out.
 As a side note, it feels very clumsy to have to manually call changed
 line functions when calling ml_* funcs - is there some notes I can
 read about why this is?
 Anyhow, here is the code I'm using to put chars in a buffer - I really
 appreciate any thoughts, this feels so close to working, but I've
 spend several hours trying to get it right.  Very frustrating :)

 Cheers
 Brad

 static void vim_append_char (buf_T target_buf, char c)
 {
static char string[2] = {0};
Should not you have = {0, 0} here?  Second element never get
initialized but it could be accessed by ml_append_string.


That might be more clear perhaps, but when you initialize an array
like that in C, the last element is propagated for the whole array.

Cheers
Brad


Re: How to trigger a screen update from RealWaitForChar

2006-08-27 Thread Brad Beveridge

SNIP 

 Q1) Is using ml_append from (effectively) within RealWaitForChar a bad
 thing?  At the moment it appears to work properly.

Yes.  You never know where in Vim you are, the caller may not handle the
situation that the text changes unexpectedly.  It's similar to
autocommands, which have caused crashes in the past.

At what level in the stack is it safe to call ml_append, etc?  How do
I tell Vim to retreat up to that level, is there code that I can look
at?  At the moment I'm trying to do it by adding to an entry to
keymap.h:key_extra, pushing 3 bytes into buf in os_unix.c (just like
the cursorhold), but I have no idea how to get right out into
main_loop.

Cheers
Brad


Re: Fastest way to append line or char to a buffer

2006-08-27 Thread Brad Beveridge

On 26/08/06, Brad Beveridge [EMAIL PROTECTED] wrote:
SNIP


Cheers
Brad


Hi, sorry for all the trouble :)  I'm having redraw issues, where
running this code to append chars is causing strange problems.
The scenario is this (always using the code below for char output):
1) Write a char to a buffer (line1)
2) Write a newline (line 2)
3) Move the cursor to the bottom of the buffer (line2 empty)
4) Write another Char (appears in line2)
5) Press Ctrl-L
6) Notice that line1 has vanished.

moving the cursor to the new blank line at the bottom of the line is
critical here.  I'm sure that I'm doing something wrong, but I really
can't figure it out.
As a side note, it feels very clumsy to have to manually call changed
line functions when calling ml_* funcs - is there some notes I can
read about why this is?
Anyhow, here is the code I'm using to put chars in a buffer - I really
appreciate any thoughts, this feels so close to working, but I've
spend several hours trying to get it right.  Very frustrating :)

Cheers
Brad

static void vim_append_char (buf_T target_buf, char c)
{
   static char string[2] = {0};
   buf_T *savebuf = curbuf;
   curbuf = target_buf;
   int start_line = curbuf-b_ml.ml_line_count;
   int lines_changed = 0;

   string[0] = c;
   if (string[0] == '\n')
   {
   ml_append (start_line, , 0, FALSE);
   lines_changed = 0;
   }
   else
   ml_append_string (start_line, string, -1);
   changed_lines (start_line, 0, start_line, lines_changed);

   /* restore and return */
   curbuf = savebuf;
}


Re: How to trigger a screen update from RealWaitForChar

2006-08-24 Thread Brad Beveridge

I have gathered together the network_io patch as best I can.  The
author is Jim Bailey, not me - however Jim is currently roaming about
in the world and was unable to respond to my requests for permission
to distribute this code.  Jim did include the standard Vim license
comments in his files, and other members on the Slim-Vim list agree
that he would want his code in the main Vim tree.

Author : Jim Bailey
Purpose : Add functions to Vim that enable callbacks on file
descriptors.  This is particularly useful for scripts that wish to
listen to a socket and trigger some code to run when a socket gets
data.
When callbacks return true, they effectively send a flag up the stack,
where update_screen is called from getchar.c
Known bugs : Callback code can write text to buffers, when the
callback triggers screen_update, the syntax colouring can go the wrong
colour.  I used dmalloc to track memory, and there is some broken
memory in syntax.c - sorry I can't be more specific right now.
Potential issues :
- The update_screen call might be happening at the wrong place and
the wrong time.
 - The callback occurs deep in RealWaitForChar, and script code can
potentially call any exposed Vim function.  This might be a Bad Thing,
I'm not familiar enough with Vim internals to know.
- Callbacks MUST drain data from the file descriptor, otherwise there
will be a loop that hangs Vim, always calling the callback.
Patch specific bugs: (These are all my fault)
- I recorded the patch the wrong way around, it must be applied with
patch -R ...
 - I am not familiar with autoconf stuff, so this patch does not
integrate with the make system of Vim, somebody probably needs to add
it to config.in.  There were too many diffs in the various files that
I thought to check, and I didn't want to over patch them.

I think that's it.  I'd love to hear any feedback about this patch.
It would be fantastic if others found this useful.

Cheers
Brad


network_io.patch.gz
Description: GNU Zip compressed data


Re: Fastest way to append line or char to a buffer

2006-08-22 Thread Brad Beveridge

On 22/08/06, Bram Moolenaar [EMAIL PROTECTED] wrote:


Brad Beveridge wrote:

SNIP


Thanks for making this patch.

No problem - it happened to be my particular itch :)


I wonder how you create a new line.  Using the old mechanism you mostly
end up reallocating the line at the next insert.  Allocating a bit of
room to anticipate further appends would be more efficient.

I'm sorry, I don't understand quite what you mean with that comment.
Do you mean if you only used ml_append_string, how do new lines ever
get created?  If you do mean that, then the answer is: new lines need
to be created by an upper level function.  I have an upper level
append_char function that is more or less:
void append_char (buf, char) {
 static uchar string[2] = {0};
 curbuf = buf;
 if (char == '\n')
ml_append // create a new line
 else
{
   string[0] = char;
   ml_append_string (string)
...
The reason that I didn't do new line creation in append_string is that
you would need to check all incoming strings for newlines, the upper
level layers can better do this check because they have more
information about the incoming string - they could know it will never
contain newlines.


Also, for appending to a different line than before you copy the line
twice.  You can avoid that by using vim_strnsave() instead of
vim_strsave() and reserving space for new characters right away.


Yes, this is a slight inefficiency.  The main reason that I did this
was that I wanted all the code to do with re-allocation in the same
place, ie the next if block.  Looking at the code again now, the
solution is probably to not copy in the cache miss code, where we
flush - just do
curbuf-b_ml.ml_line_ptr = ml_get(lnum);

Cheers
Brad


Re: Fastest way to append line or char to a buffer

2006-08-22 Thread Brad Beveridge

On 22/08/06, Bram Moolenaar [EMAIL PROTECTED] wrote:



SNIP


I understand.  It would be a bit more efficient if the new, empty line
that you add when a newline is encountered already has room for a
certain number of characters.

Ah, I see.  True, but since I don't know the code base that well I
didn't want to touch too much code all over the place.



  Also, for appending to a different line than before you copy the line
  twice.  You can avoid that by using vim_strnsave() instead of
  vim_strsave() and reserving space for new characters right away.

 Yes, this is a slight inefficiency.  The main reason that I did this
 was that I wanted all the code to do with re-allocation in the same
 place, ie the next if block.  Looking at the code again now, the
 solution is probably to not copy in the cache miss code, where we
 flush - just do
 curbuf-b_ml.ml_line_ptr = ml_get(lnum);

I suppose that should work (didn't look at it carefully).

I might have a look later if this code can be used in certain
situations.  That should make some operations work faster, e.g. pasting
a large chunk of text into a terminal emulator.


I think it will work from the quick glance over it.  I can test it
more throughly tonight.  I'd love it if I made an actually useful
contrib to Vim - I love this editor, thanks for writing it!

Brad


Re: Fastest way to append line or char to a buffer

2006-08-20 Thread Brad Beveridge

The last code I posted was a little broken.  Here is a patch that
appears (after a reasonable amount of testing) to work quite well for
very quickly appending chars to a vim line.
As I said, scripting language authors that use Vim output buffers as
STDOUT style streams could use this to good advantage.

Cheers
Brad


append-char.patch.gz
Description: GNU Zip compressed data


How to trigger a screen update from RealWaitForChar

2006-08-18 Thread Brad Beveridge

Hi all, I'm working with a Vim that has been hacked so that you can
get callbacks when data appears on a socket.
Basically, our callback system works in pretty much the same way as
the code in FEAT_SNIFF.  We add the filedescriptors that we are
interested in to the select/poll code in os_unix, if there is data
pending on a socket then we callback a registered function, which
should clear the data from the socket.
In my particular case, the callback calls into Lisp code in our
embedded Lisp interpreter, which writes data to buffers using
ml_replace and ml_append.

Q1) Is using ml_append from (effectively) within RealWaitForChar a bad
thing?  At the moment it appears to work properly.

At the moment, after the callback has run we call
screen_update(NOT_VALID).  However, from what I can see, calling
screen_update may (does?) re-call RealWaitForChar, which can retrigger
the callback, etc.
Q2) Is this nesting of RealWaitForChar a bad thing? (I thing it may be)

Q3) What is the correct way/place to trigger screen_update(NOT_VALID)?
How should I trigger it from within RealWaitForChar?

One other point to consider, although we may do callbacks,
RealWaitForChar may not have keyboard input - what should
RealWaitForChar return in this case?

If the list would like to see this code, I can post a patch, or you
can use Darcs to get a Vim+Callbacks+ECL from
http://theclapp.org/repos/vim70+async+ecl/.

Q4) Would this callback mechanism be more generally useful for other
scripting engines?

Cheers
Brad


Re: Fastest way to append line or char to a buffer

2006-08-18 Thread Brad Beveridge

On 16/08/06, Brad Beveridge [EMAIL PROTECTED] wrote:

On 16/08/06, Bram Moolenaar [EMAIL PROTECTED] wrote:

 Brad -

  As a side note, if I wanted to get really fast char append, how does
  this method sound:
  1) In a structure (not sure if a mem_line or bufT struct), have three
  new entries
  uint current_line_num;
  uchar *current_line_buffer;
  uint current_line_alloced;
  2) current_line_buffer points to the string data for the current line,
  it starts off at a sane size (say 80, or screen_width), and doubles in
  alloced size when it is too full.
  3) ml_append_char (or whatever I call it), will check the target line
  number against current_line_number, if the match then
- append the char, possibly reallocing the current_line_buffer if we
  have run out of space
  ELSE, the edit line number and our cached line don't match
- trim the size of the current_line_buffer to match the STRLEN of the line
- alloc a new oversized line buffer and copy the new edit line into it
- append the char as above

 Vim caches the last changed line, you could do something with that.
 Start looking at ml_flush_line(), you can find the rest from there.

  Would this kind of optimisation be more widely useful?

 Perhaps.  Changing the same line several times is not unusual.  It
 mostly depends on how much code would need to be changed compared to
 how much we would gain.

 - Bram


Thanks for the tips, I'll test all this out and see what I can come up
with.  I also accidentally posted just to Bram, so I've included the
list in this reply.

Thanks
Brad


I ended up writing a string append function, that has sped up my
output code by a couple of orders of magnitude :)  Here it is, does it
look sane?

Cheers
Brad

/*
* Append string to line lnum, with buffering, in current buffer.
*
* Always makes a copy of the incoming string
*
* Check: The caller of this function should probably also call
* changed_lines(), unless update_screen(NOT_VALID) is used.
*
* return FAIL for failure, OK otherwise
*/
   int
ml_append_string(lnum, string, slen)
   linenr_Tlnum;
   char_u  *string;
   int slen;
{
   int append_len = 0;
   int line_len = 0;
   if (slen == -1)
   append_len = STRLEN(string);
   else
   append_len = slen;
   if (string == NULL) /* just checking... */
   return FAIL;

   if (lnum == 0)
   ml_append (lnum, string, slen, 0);

   /* When starting up, we might still need to create the memfile */
   if (curbuf-b_ml.ml_mfp == NULL  open_buffer(FALSE, NULL) == FAIL)
   return FAIL;

#ifdef FEAT_NETBEANS_INTG
   /*
#error I am 99% sure this is broken
   if (usingNetbeans)
   {
   netbeans_removed(curbuf, lnum, 0, (long)STRLEN(ml_get(lnum)));
   netbeans_inserted(curbuf, lnum, 0, string, (int)STRLEN(string));
   }
   */
#endif
   if (curbuf-b_ml.ml_line_lnum != lnum)  /* other line buffered */
   {
   ml_flush_line(curbuf);  /* flush it, this frees
ml_line_ptr */

   /* Take a pointer to the existing line, will get re-alloced right
* away below because it is not big enough */
   curbuf-b_ml.ml_line_ptr = vim_strsave(ml_get(lnum));
   curbuf-b_ml.ml_line_len = STRLEN(curbuf-b_ml.ml_line_ptr);
   curbuf-b_ml.ml_line_lnum = lnum;
   }
   /* By here,
* curbuf-b_ml.ml_line_ptr - is filled with the correct existing line
* curbuf-b_ml.ml_line_len - is the alloced size of the line
*/
   line_len = STRLEN(curbuf-b_ml.ml_line_ptr);
   if (curbuf-b_ml.ml_line_len  line_len + append_len + 1)
   {
   int new_len = (curbuf-b_ml.ml_line_len + line_len + 1) * 2;
   char_u *new_line;
   if (new_len  80) new_len = 80;
   new_line = vim_strnsave(curbuf-b_ml.ml_line_ptr, new_len);
   vim_free(curbuf-b_ml.ml_line_ptr);
   curbuf-b_ml.ml_line_ptr = new_line;
   curbuf-b_ml.ml_line_len = new_len;
   }
   /* by here:
* ml_line_ptr is allocated to fit the current line + the append
* ml_line_len is the total alloced size of the line
*/
   STRCPY (curbuf-b_ml.ml_line_ptr[line_len], string);  /* Append
our string */
   curbuf-b_ml.ml_line_ptr[line_len + append_len] = NUL; /* End the line */
   curbuf-b_ml.ml_flags = (curbuf-b_ml.ml_flags | ML_LINE_DIRTY)  ~ML_EMPTY;

   return OK;
}


Re: Fastest way to append line or char to a buffer

2006-08-16 Thread Brad Beveridge

On 16/08/06, Bram Moolenaar [EMAIL PROTECTED] wrote:


Brad -

 As a side note, if I wanted to get really fast char append, how does
 this method sound:
 1) In a structure (not sure if a mem_line or bufT struct), have three
 new entries
 uint current_line_num;
 uchar *current_line_buffer;
 uint current_line_alloced;
 2) current_line_buffer points to the string data for the current line,
 it starts off at a sane size (say 80, or screen_width), and doubles in
 alloced size when it is too full.
 3) ml_append_char (or whatever I call it), will check the target line
 number against current_line_number, if the match then
   - append the char, possibly reallocing the current_line_buffer if we
 have run out of space
 ELSE, the edit line number and our cached line don't match
   - trim the size of the current_line_buffer to match the STRLEN of the line
   - alloc a new oversized line buffer and copy the new edit line into it
   - append the char as above

Vim caches the last changed line, you could do something with that.
Start looking at ml_flush_line(), you can find the rest from there.

 Would this kind of optimisation be more widely useful?

Perhaps.  Changing the same line several times is not unusual.  It
mostly depends on how much code would need to be changed compared to
how much we would gain.

- Bram



Thanks for the tips, I'll test all this out and see what I can come up
with.  I also accidentally posted just to Bram, so I've included the
list in this reply.

Thanks
Brad


Fastest way to append line or char to a buffer

2006-08-15 Thread Brad Beveridge

Hi all,
I'm working with a Vim that has been patched to support ECL Lisp
(http://wiki.alu.org/Vim_ECL).  Part of our project involves
outputting potentially large amounts of data  to a buffer in a
streaming fashion, ie always adding at the end.
I think that I have worked out a reasonable way to append lines[1],
but I can't see any obvious way to quickly append single chars to a
buffer.
Are there any functions like ml_append I can look to for this support?
How should I go about appending single chars very quickly?

Cheers
Brad

[1] Here is the append code that I hacked up tonight

static cl_object cl_vim_append_lines_int (cl_object buf, cl_object lines)
{
   buf_T *savebuf = curbuf;
   curbuf = ((buf_T *)ecl_foreign_data_pointer_safe(buf));
   int start_line = curbuf-b_ml.ml_line_count;

   while (lines != Cnil) {
   char_u *line = string_to_line (cl_car (lines));
   ml_append (curbuf-b_ml.ml_line_count-1, line, 0, FALSE);
   vim_free (line);
   lines = cl_cdr (lines);
   }
   changed_lines(start_line, 0, curbuf-b_ml.ml_line_count,
(long)(curbuf-b_ml.ml_line_count - start_line));

   /* restore and return */
   curbuf = savebuf;
   return Ct;
}


Fwd: Extra file descriptor callbacks

2006-06-18 Thread Brad Beveridge

I accidentally posted to individuals, not the list - damn Gmail!
Brad

On 16/06/06, John (Eljay) Love-Jensen [EMAIL PROTECTED] wrote:

Emacs can do everything:  it's an editor, an environment, an operating system 
(in the same sense that JVM is an operating system), and a religion.  The only 
thing emacs lacks is a good editor.  And now, emacs would have a fantastic 
editor: Vim!


I'm not sure if I am reading you right, but we are not aiming for any
sort of Emacs compatibility.  Slime is a debugger for Lisp, it has two
parts a backend that runs in a Common Lisp image called Swank, and a
frontend that runs in Emacs and is written in ELisp (Emacs' Lisp
dialect).
Our project is attempting to re-implement the frontend only, we will
crib code heavily from the existing Slime frontend, but Elisp is not
the same as CLisp so some stuff will need to be different.  And of
course, Slime relies heavily on Emacs specific drawing functions that
won't port at all.

Really the only relationship we have to Emacs is there is an existing
code base with the functionality we need, and that existing base
happens to run in Emacs.

Cheers
Brad


Fwd: Extra file descriptor callbacks

2006-06-18 Thread Brad Beveridge

Repost: to the actual list this time:

On 16/06/06, Yakov Lerner [EMAIL PROTECTED] wrote:

On 6/16/06, Bram Moolenaar [EMAIL PROTECTED] wrote:
 Brad Beveridge wrote:
  Hello all, I am involved in a project that has embedded ECL
  (http://ecls.sourceforge.net/), a Lisp interpreter into Vim.

Is the next goal of this project to have emacs runnnig inside
List interpreter inside Vim :-) ?


Heaven forbid!!! :)  The main goal of the project is to get Slime
(http://common-lisp.net/project/slime/) running in Vim.  Slime is a
Lisp debugger that uses Emacs as the frontend, and the Emacs side is
written in ELisp.  Just trying to make it so Emacs isn't the only
decent Lisp development environment :)

Cheers
Brad


Extra file descriptor callbacks

2006-06-12 Thread Brad Beveridge

Hello all, I am involved in a project that has embedded ECL
(http://ecls.sourceforge.net/), a Lisp interpreter into Vim.  Our end
goal for the project involves having Lisp code inside of Vim respond
to incoming data from a socket, so we also have a patch that allows us
to register callbacks that will be triggered when we receive data on a
file descriptor.
The code for this is here http://theclapp.org/repos/.  The async
callback patch only really works for GTK and console I think.
Basically all the patch does is add a few more file descriptors to
poll/select on during Vim's read_char, if the appropriate descriptor
is triggered then we get a callback to Lisp.

The callbacks all appear to work fine, for example you can setup a
listening socket in Vim and have data output to a Vim buffer without
any problems.  But there is a bug.  Lets assume that we have a server
that simply echoes back data, and a client that sends data.
Data flow is something like:
(CLIENT) Embedded Lisp script sends data
(SERVER) Echoes data back
(CLIENT) Still sending data, there is also pending data coming back
from the server
(CLIENT) Finishes sending data, next time through the read_char loop
should trigger call back which will read data out from the socket.

However, the CLIENT side crashes in this scenario, it appears to crash
inside the Lisp interpreter.  I suspect that somehow the last two
phases above are overlapping, and the interpreter is being re-entered,
which I don't think it supports.  However, I don't see how this can be
happening - as far as I am aware Vim is totally single threaded (at
least *nix console builds), so the behaviour should be deterministic,
the data will finish sending, continue out to the main loop and then
trigger the callback.

I know it is a lot to ask for help on such a modified Vim, but this is
really starting to get me down.  I would really appreciate any
thoughts about what might be going on, or how to debug this.

Cheers
Brad