don't set unbuffered unless they've already printed the prompt.
This avoids printing the prompt before the application has a chance
to process the input line.
From sjg@
Patch from Yen Chi Hsuan in the PR, extracted from Apple's version of
readline.c, then modified by me to be consistent about what the return
value really is.
PR/51518: Jay West: prompt is interleaved with client output
Both these issues are caused by rl_restore_handler not DTRT; fix
it so that it kills the internal libedit state completely. This is
inefficient, but it works.
Also fix:
1. add append_history()/H_NSAVE_FP
2. call the rl_startup_hook before printing the first prompt as documented.
callint it from rl_initialize breaks python, because the callback ends
up being invoked before the readline module is installed, and we end up
dereferencing a NULL pointer.
3. add el_resize_terminal.
With those changes, s/lreadline/ledit/g in python works.
In libedit, the only way how H_ENTER can fail is memory exhaustion,
too, and of course it is handled gracefully, returning -1 from
history(). So of course, we will continue to handle it gracefully
in add_history() as well, but we are free to decide what to do with
the library state in this case because GNU just dies...
I think the most reasonable course of action is to simply not change
the library state in any way when add_history() fails due to memory
exhaustion, but just return.
If H_ENTER does not fail, we know that the history now contains at
least one entry, so there is no need any longer to check the H_GETSIZE
return value. And we can of course always set current_history_valid.
While testing these changes, i noticed three problems so closely
related that i'd like to fix them in the same diff.
1. libedit has the wrong prototype for add_history().
GNU readline-6.3 defines it as void add_history(const char *).
Of course, that is very stupid - no way to report problems to
the caller! But the whole point of a compatibility mode is
being compatible, so we should ultimately change this.
Of course, changing the prototype of a public symbol requires
a libedit major bump. I don't want to do that casually.
Rather, i will take a note and change the prototype the next
time we need a libedit major bump for more important reasons.
For now, let's just always return 0.
2. While *implicitely* pushing an old entry off the history
increments history_base in GNU readline, testing reveals that
*explicitly* deleting one does not. Again, this is not
documented, but it applies to both remove_history() and
stifle_history(). So delete history_base manipulation
from stifle_history(), which also allows to simplify the
code and delete two automatic variables.
3. GNU readline add_history(NULL) crashes with a segfault.
There is nothing wrong with having a public interface
behave that way. Many standard interfaces do, including
strlen(3). Such crashes can even be useful to catch
buggy application programs.
In libedit/readline.c rev. 1.104, Christos made add_history()
silently ignore this coding error, according to the commit
message to hide a bug in nslookup(1). That change was never
merged to OpenBSD. I strongly disagree with this change.
If nslookup(1) is still broken, that program needs to be
fixed instead. In any case, delete the bogus check; hiding
bugs is dangerous.
Even though section "2.3.3 Information About the History List"
of the history(3) info(1) manual only says
-- Function: int where_history (void)
Returns the offset of the current history element.
which maybe isn't completely clear, a plausible implementation
is that the offset returned is the same offset that can be used
for history_set_pos(), i.e. that it is 0 for the oldest entry
and increases with time, and that's how the GNU implementation
behaves indeed.
The libedit implementation, on the other hand, returns 1 for the
newest entry and increases going back in time.
perspective of the dawn of time, so "next" means "newer" and "previous"
means "older". Libedit, by contrast, uses reverse chronology and
regards history from the perspective of the present, such that "next"
means "longer ago" and "previous" means "not so long ago".
The following patch fixes previous_history() and next_history()
as proposed by Bastian Maerkisch.
But there is a related problem demonstrated by Bastian's regression
tests that his patch did not fix: next_history() can advance not
only to the newest entry, but beyond it, which core libedit cannot
do. So that feature must be implemented locally in readline.c.
With that, the last of Bastians tests is fixed, test_movement_direction().
This patch also improves libedit documentation to more clearly state
what "previous" and "next" mean. GNU readline documentation is
just as unclear, but we can't easily fix that since libedit doesn't
include its own readline.3 manual.
(Ingo Schwarze)
implementation: libedit goes to the entry with the given number
stored in the HistEvent structure, while GNU subtracts history_base,
then advances that many entries from the oldest one. If entries were
removed in between, GNU advances further than libedit.
The call sequence H_CURR, H_DELDATA, H_CURR, H_NEXT_EVDATA looks
weird, as if part of that must somehow be redundant. But actually,
the user interface is so counter-intuitive that every single step
is really required.
- The first H_CURR is needed to be able to go back after an error.
- The H_DELDATA is needed to move the cursor. Even though it takes
a pointer to ev, that structure is not filled in when the call
succeeds. H_DELDATA only moves the cursor, it doesn't tell us
the new event number.
- Consequently, the second H_CURR is required to get ev.num filled
in. But it doesn't return the data because ev has no field for
that.
- So even though the cursor is already positioned correctly,
H_NEXT_EVDATA is needed as the final step merely to get the data.
(Ingo Schwarze)
* Replace fcns.c by a shorter and simpler func.h
and include it only in the one file needing it, map.c.
* Combine help.h and help.c into a simplified help.h
and include it only in the one file needing it, map.c.
* Check the very simple, static files editline.c, historyn.c, and
tokenizern.c into CVS rather than needlessly generating them.
* So we no longer autogenerate any C files. :-)
* Shorten and simplify makelist by deleting the options -n, -e, -bc,
and -m; the latter was unused and useless in the first place.
* Move the declaration of el_func_t from fcns.h to the header
actually needing it, map.h. Since that header is already
included by el.h for unrelated reasons, that makes el_func_t
just as globally available as before.
* No longer include the simplified fcns.h into el.h,
include it directly into the *.c files needing it.
Let "el.h" include everything needed for struct editline,
and don't include that stuff multiple times. That also improves
consistency, also avoids circular inclusions, and also makes it
easier to follow what is going on, even though not quite as nice.
But it seems like the best we can do...