The `:bar` in vim doesn't work as expected - vim

After reading the vim doc about *:bar* *:\bar*:
'|' can be used to separate commands, so you can give multiple commands in one line.
I tried to clear history via this command:
:set history=0 | set history=20
I expect that, these two commands should be executed one by one, and the history should be cleared.
But it didn't. The history still there, and a new history was added.
Then I tried:
:set history=0
:set history=20
It works.
Why?

When you execute a command line that is what happens:
History is initialized (truncation happens here) (init_hist() function call in getcmdline()).
String to be executed is obtained (in getcmdline()).
It is added to history (add_to_history() call in getcmdline()).
It is executed (do_one_cmd() in do_cmdline(), happens after getcmdline() call (called by getexline() passed as fgetline argument to do_cmdline())).
Setting the option itself does nothing, it only changes p_hi variable. Actual modification of history is done at step 1.
Now let’s see what happens in both cases (assuming that you typed second or third additional command):
History is first initialized when p_hi has old value, then it is changed two times and then when you do next command it is already set to 20.
History is first initialized when p_hi has old value, then it is changed once and initialized for the second time, being effectively truncated at this step and only then the value changes again. By the time you start typing third command it is already wiped out.
Thus your assumption (commands are executed one by one) is true, but you have mistaken at which point history modification happens. I would rather suggest using histdel() as #Michael advised because, at first, it clears history by itself and, at second, it does not have hardcoded 'history' value. I can’t say how you live with just 20 lines long history (I’ve set it to 65535 and am always sure I won’t lose anything small, but useful), but hardcoding this value will make changing history size to something else more painful.

Related

How do I check if nothing was typed in the previous Zsh prompt

In the zsh prompt, I have a custom script to display the amount of time the last command ran for.
I've got this working, but how do I check if the user entered nothing and just pressed "Enter" or "Ctrl + C", in the previous prompt?
In this case, I do not want to show the amount of time the user spent idle, as this is not useful information for me.
$history[$((HISTCMD-1))] doesn't appear to work in this case. If the user typed nothing and just hit enter, it will just show the last command that was run, and not be an empty string.
If you define a function with the name zshaddhistory, it will be invoked every time enter has been pressed. $1 is the command being entered, and this can also be an empty command. You could set a global variable to indicate that an empty line has been entered, and use this variable later on.
Be careful with the return value from this function: If it returns 0, the command is saved into the history; otherwise it is not. You find more on this in the zshparam man-page, where _HISTORY_IGNORE_ is described, because the main use of this function is to control whether or not a command should be added into the history. Hence, an alternative would be to add empty lines to the history too and use your original approach with $history to access it. This has the disadvantage that seeing empty history entries is not really user-friendly.

modifying previously executed commands on linux

I want to modify a previously run command with slightly different arguments. Is there a quick way of reaching the argument which is somewhere between in the big command, instead of going to that place from beginning (or end) of the command?
Currently I wrap the big command into some small command and pass the argument to the wrapper command.
Was wondering if there was any other way.
You can press ↑ to bring the last line;
Then you can jump over the arguments with Alt+F and Alt+B.
(if you're on Mac it's Esc+F and Esc+B)
You may also type !:1 to refer to the first argument in the previous entry, or !:2 to refer to the second argument, and so on.

Vim Undo command (the one with the with capital U)

I don't understand how the undo line command works.
The documentation says Undo all latest changes on one line.
What is the definition of all latest changes here?
One behaviour I have noticed is that sometimes U undoes all writes after the very first write on a line. But this is not consistent. For example, when I open a new file and edit the first line, writing multiple times, the U command undoes every single change.
I haven't been able to find anything concrete from my google searches either.
In my understanding all latest changes means going back the change history until a change in a different line is encountered, and stop there. So if you start with an empty buffer and edit only one line (repeatedly), all additions will be wiped by U.
Vim generally merges near changes occurring in the same line; these appear as a single entry in :changes.
U: return the last line which was modified to its original state (reverse all changes in last modified line)
http://vim.wikia.com/wiki/Undo_and_Redo

Undo all changes since opening buffer in vim

How can I undo all changes since opening a buffer? I imagine there may be some form of :earlier that does this.
UPDATE: Many are suggesting solutions for traversing to earlier file writes. This isn't what I asked for. I want to return to the original state the file was in when I originally loaded it into a buffer, no matter how many writes were made since then.
To revert the current buffer to the original state prior to the very
first change recorded in its undo list (see :help undo-tree), one
can use the following two consecutive invocations of the :undo
command:
:u1|u
The first command (:undo 1) reverts to the state of the buffer just
after the very first registered change, while the second command
(:undo) reverts that first change itself.
Starting with version 8.1 (see :helpg Patch 8.0.1441), Vim accepts
the change number 0 as a valid argument to the :undo command,
finally providing a way to refer to the state prior to any registered
changes. This makes it possible to achieve the same effect in
a single-command invocation:
:u0
You can use the
:edit!
command to get into the earliest saved state. See :help edit! for more information.
You can also check something like gundo.vim (can be found here), which displays the whole undo tree graphically, and you can easily jump between points. Then there is the histwin plugin which I did not used yet, but offers similar functionality.
In vim 8.1+ as well as in neovim, you can just use :u0
From the documentation
:u[ndo] {N} Jump to after change number {N}. See |undo-branches|
for the meaning of {N}. {not in Vi}
If you type
:u 1
it appears to go to after the first change; pressing u or typing :u will then go back to the change.
Otherwise, you can use a very large count to :earlier or g-
e.g.
:earlier 100000000 or 100000000g-
If you put this into a mapping/command, it could do any of these without too much trouble.
e.g.
:nnoremap <C-F12> :earlier 100000000<CR>
To access previously saved file status, I think the following work :
:earlier 1f
From the documentation :
:earlier {N}f Go to older text state {N} file writes before.
When changes were made since the last write
":earlier 1f" will revert the text to the state when
it was written. Otherwise it will go to the write
before that.
When at the state of the first file write, or when
the file was not written, ":earlier 1f" will go to
before the first change.
:earlier {N}m Go to older text state about {N} minutes before.
That should help... And even you have {N}h which is about {N} hours before.
A graphic solution:
The Gundo plugin allows visual comparison of changes in the undo history.
Open Gundo's "undo history pane", type G go to the last line, then we can back to the original file.

How to have history in two files in linux

Is is possible to have the history of a specific user in one more file other than the default file mentioned as HISTFILE?
I would like to have as backup file if main file was removed and let it be like a backup for that one.
Regards,
Sriharsha Kalluru.
You can create a hardlink to the file
cp --link --verbose /home/$USER/.bash_history /somewhere/else/users_history
When the original file in his home is removed the file is still there and preserves the content from being lost.
Many times I've found myself using Ctrl-R in Bash to get a old command four times the terminal width, just to find out that too many days have passed and it's no longer in the .bash_history file. Here are two lines that will keep track of every command line you type at the bash prompt and use no external processes at all, just plain bash.
My first approach to this problem was increasing the maximum number of lines in the history to a very large quantity. But no matter how large it was, there was always a moment when I needed a long command I typed many months ago and it had already left the history. The current solution came to my mind when I learned about the PROMPT_COMMAND variable, a command that bash executes before showing each prompt. Here are the two lines:
export HISTTIMEFORMAT="%s "
PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND ; }"'echo $$ $USER \
"$(history 1)" >> ~/.bash_eternal_history'
One goal I set to myself was to achieve it without using any external process, so bash wouldn't have to fork a new process after every ENTER pressed at its prompt. The first line sets the format of history lines to include the date as a Unix timestamp, so you can now when you typed every command. The second line, which is the core of the solution, first ensures that, if a previous PROMPT_COMMAND was set, it gets executed before our stuff and then appends a line of the format:
PID USER INDEX TIMESTAMP COMMAND
to a file called .bash_eternal_history in the current user home.
Adding the username, which at first seemed unnecesary, became useful later to distiguish between "sudo -s" sessions and normal sessions which retain the same value for "~/", and so append lines to the same .bash_eternal_history file.
I hope some of you find these two lines as useful as I do. :-)
Would hard links solve your problem?
Also you can read the man page here.
i would write a cronjob that copies the original histfiel to a backuplocation every minute or so. the you don't have to worry about defining a second histfile.
otherwise you could write every command the user enters to a alternate file
for this approach take a look here:
bash, run some command before or after every command entered from console

Resources