Ticket #40964

per-session history

Open Date: 2020-11-15 07:28 Last Update: 2021-02-14 21:50

Reporter:
(Anonymous)
Owner:
(None)
Status:
Open
Component:
(None)
MileStone:
(None)
Priority:
5 - Medium
Severity:
5 - Medium
Resolution:
None
File:
None
Vote
Score: 0
No votes
0.0% (0/0)
0.0% (0/0)

Details

i find it very confusing/disturbing that when i enter a command in one terminal, let's say in ~/project1, and then switch to another terminal which is in ~/project2, and hit cursor-up, to *not* get the last command i entered in that very same terminal, but the one i entered in project1. i've studied the manual to see whether i can make the behaviour like in bash, but it doesn't seem to be possible at the moment. please consider adding this as a configuration option, because it is annoying to such a degree that i consider to switch back to bash, even though yash is much nicer in many other aspects. it already happened to me several times that i hit cursor-up-enter as i'm accustomed to to repeat the last command (like e.g. "make") but instead have a completely unrelated command show up (and starting), like youtube-dl something. i know that bash loses some commands of the history (afaik it writes to .bash_history whenever the bash session is closed from the point where the history file was when that shell was started), but that's not really an issue for me. the optimal behaviour in my opinion would be that yash keeps updating the history file as it does currently, but doesn't reload its contents after a change in active sessions, so the current yash session stays unaware of commands entered in other shells.

Ticket History (3/14 Histories)

2020-11-15 07:28 Updated by: None
  • New Ticket "per-session history" created
2020-11-18 06:38 Updated by: None
Comment

head 1===

i came up with a patch that makes the behaviour as in bash, however it seems some junk is written in the histfile.

patch follows, unfortunately i didnt find out what markup language this forum uses.

https://0x0.st/i59D.patch

<pre> this patch makes it so history between yash instances isn't synchronized and never reloaded from file during a session. on exit it's written to file as usual. this is just like the behaviour of bash.

yash's default behaviour is that you enter a command in term1, then hit cursor-up in term2, and you suddenly have the command from term1 in the history.

diff --git a/history.c b/history.c index 6e9143b..86a8524 100644 --- a/history.c +++ b/history.c @@ -1062,7 +1062,7 @@ void add_history(const wchar_t *line)

if (histfile != NULL)
lock_histfile(F_WRLCK);
update_time();

- update_history(true); + //update_history(true);

for (;;) {
size_t len = wcscspn(line, L"\n");

@@ -1141,6 +1141,7 @@ const histlink_T *get_history_entry(unsigned number)

/* Calls maybe_init_history' or update_history' and locks the history. */ void start_using_history(void) {

+#if 0

if (!hist_lock) {
if (histfile != NULL) { lock_histfile(F_RDLCK);

@@ -1153,12 +1154,17 @@ void start_using_history(void)

} hist_lock = true;
}

+#else + update_time(); +#endif

} /* Unlocks the history. */ void end_using_history(void) {

+#if 0

hist_lock = false;

+#endif

} #endif /* YASH_ENABLE_LINEEDIT */

diff --git a/yash.c b/yash.c index 66e8cb3..6d7bd6e 100644 --- a/yash.c +++ b/yash.c @@ -236,6 +236,12 @@ int main(int argc, char **argv)

shell_initialized = true;

+#if YASH_ENABLE_LINEEDIT + /* if line editing and interactive and connected to a terminal, start history */ + if (is_interactive && isatty(STDIN_FILENO) && isatty(STDERR_FILENO)) + maybe_init_history(); +#endif +

if (shopt_cmdline)
exec_wcs(input.command, inputname, true);
else

</pre>

2020-11-22 12:05 Updated by: magicant
Comment

Thank you for the feature request.

I used to think the bash-like behavior could be implemented by tweaking the yashrc file, but now I think that will not fully work since the abilities of the history and fc built-ins are limited. I consider adding an option to switch the behavior.


Some workarounds that can be done in the current version of yash:

Unset the HISTFILE variable in yashrc, then yash instances do not share history, but the history is lost when you close yash. To save history over sessions, use the history built-in to save and load the history to and from a file. To save the history automatically when the shell is closed, set the EXIT trap in yashrc. Note that this will overwrite history that may have been written by another shell instance.

2020-11-22 15:17 Updated by: None
Comment

thanks for your reply. what came to my mind after spending a couple hours with history.c was that instead of writing pid on start and end, every line could be prefixed by pid in hex, afaik pid can never be > 0xffff so 4 bytes additional should be sufficient. on start the entire hist file is loaded, but after that only lines with own pid will be added to history in "bash mode", in yash mode any. i didn't actually figure out the current purpose of saving the pids, but i saw in strace that other pids active were "killed" - maybe a signal sent? though i dont think this is actually necessary when flock() is used. alternatively the file can be opened in append-only mode, but then duplicates can't be removed (although the writing process could simply not write commands it has buffered in memory).

2020-11-22 15:52 Updated by: magicant
Comment

Yash saves PIDs in the history file and sends signals to other yash processes in order to check if there are other yash processes sharing the same history file. To prevent the command number of history items from increasing forever, yash resets the command number after removing old items, counting from 1 again. This is done only when there are no other shell processes because POSIX requires to do so.

2021-01-27 10:46 Updated by: None
Comment

hi magicant, i installed release 2.51 and to my surprise the issue seems gone after some initial testing. did you make some changes in this regard? when i skimmed over the commit history i didn't see anything directly related.

2021-01-27 23:42 Updated by: magicant
Comment

Strange... This issue is not yet addressed in the last release.

2021-02-08 14:19 Updated by: None
Comment

indeed, it's strange. it seemed to work while yash wasn't set as my login shell in /etc/passwd, i.e. when i started it manually from within a bash session. after making it my login shell and reboot, the behaviour went back to what is described here in the ticket, highly annoying, to the point of driving me crazy.

meanwhile i gave a try to your recommendation of using the history builtin instead. my attempt looks like so in .yashrc:

#HISTFILE=~/.yash_history HISTSIZE=5000
#set --hist-space
MYHISTF=~/.yash_history_raw
test -e "$MYHISTF" || touch "$MYHISTF"
upd_hist() {
history -w "$MYHISTF".$$
{
 flock -x 3
 cp "$MYHISTF" "$MYHISTF".$$.tmp
 comm -3 "$MYHISTF".$$.tmp "$MYHISTF".$$ >> "$MYHISTF"
 flock -u 3
} 3>"$MYHISTF".lock
rm -f "$MYHISTF".$$ "$MYHISTF".$$.tmp "$MYHISTF".lock
}
history -r "$MYHISTF"
trap upd_hist TERM EXIT HUP

however it always results in "history: cannot be used during line-editing" when i close the terminal (SIGHUP), whereas i can run "history -w foo.txt" just fine from within the interactive shell. the manpage doesn't mention how line-editing can be turned off. interestingly, after getting that error message the terminal doesn't close, it's gotten into an unkillable state...

P.S: i finally found formatting guide for this wiki https://osdn.net/docs/WikiSyntax

2021-02-09 08:01 Updated by: None
Comment

update: comm -3 in the above code needs to be changed to comm -13, otherwise the new history block will be indented by one tab (at least with busybox comm). apart from that it now works splendidly with the builtin history solution, other than that SIGHUP doesn't work, which means the history is lost if e.g. X11 crashes or i issue "reboot" or "poweroff" from a terminal, or even when closing a terminal using the X button.

2021-02-09 08:19 Updated by: None
Comment

hmm, i realized that comm -13 will omit lines added in the meantime by other processes, also according to man 1p input needs to be sorted, so it is useless here. this seems to work better, and requires less temporary files:

#HISTFILE=~/.yash_history HISTSIZE=5000
#set --hist-space
MYHISTF=~/.yash_history_raw
test -e "$MYHISTF" || touch "$MYHISTF"
MYHISTF_LINES=$(wc -l "$MYHISTF" | cut -d " " -f 1)
upd_hist() {
history -w "$MYHISTF".$$
nl_count=$(wc -l "$MYHISTF".$$ | cut -d " " -f 1)
added=$((nl_count - MYHISTF_LINES))
{
 flock -x 3
 tail -n $added "$MYHISTF".$$ >> "$MYHISTF"
 flock -u 3
} 3>"$MYHISTF".lock
rm -f "$MYHISTF".$$ "$MYHISTF".lock                  
}
history -r "$MYHISTF"
trap upd_hist TERM EXIT
might even be possible to use flock with the file option in this case and run tail... as the command argument it requires.

2021-02-10 01:06 Updated by: magicant
Comment

The line-editing feature is active while the shell is showing the prompt and waiting for command input. Because the feature accesses the command history to allow recalling previous commands, the history cannot be otherwise accessed until you hit the Enter key to finish the current line of input.

By the way, you would probably want to invoke the exit command explicitly in your trap command to terminate the shell gracefully. Otherwise, the shell will survive the SIGHUB signal and keep reading commands.

2021-02-11 04:06 Updated by: None
Comment

thanks for your reply. do you have a recommendation how i could properly deal with SIGHUP ? i hoped that adding trap exit HUP would cause the exit handler to get called, but that doesn't seem to be case - the history is not being saved, unlike when i exit the shell with CTRL-D. alternatively i need a way to force yash out of its "wait for command input" mode so i can use the history builtin in the sighup handler.

2021-02-13 00:41 Updated by: magicant
Comment

This might work:

trap 'exec </dev/null' HUP
trap '# do what you want to do before the shell exits' EXIT
2021-02-14 21:50 Updated by: magicant
Comment

I was thinking of adding two options to change the shell's behavior. The first option can be used to disable the shell from reading new commands from the history file written by other shell instances. The second option makes the shell write the history when the shell exits rather than each time a new command is entered.

The second option, however, turned to be harder to implement than I thought at first. More precisely, changing when to write the history is not that hard, but it introduces possibility of accidental loss of history since the shell might be killed by a signal before it writes the history on exit. For safety, the shell should install signal handlers that catch signals that would kill the shell, and that will complicate the existing signal handling logic.

For now, I'm considering adding only the first option rather than implementing the both options at once.

Attachment File List

No attachments

Edit

You are not logged in. I you are not logged in, your comment will be treated as an anonymous post. » Login