I want to match newline character in test case of an if statement in vim script.
How do I match to a newline character ?
The reason for this is, when I want to get the output of a system command and check if it matches something, and then execute a command, the system() command in vim can do the work, but it returns with a newline at the end. So I am not able to match properly.
For example, I hope you know about git rev-parse --is-inside-work-tree, it prints true with a newline at the end if we are inside a git repository, and false with a newline at the end if we are not inside a git repository.
I want to use this command inside vim script and run a command only if I am inside a git repository.
But since this command returns true or false with a newline at the end, I am unable to use the following snippet of code to do this. Because system("git rev-parse --is-inside-work-tree") returns true or false with a newline at the end.
if system("git rev-parse --is-inside-work-tree") == 'true'
echo "Inside a git repository"
else
echo "Not inside a git repository"
endif
What can I use instead of if system("git rev-parse --is-inside-work-tree") == 'true' to match newline at the end ?
You can use "true\n" to check the newline. Note that double quotes are used for special characters. See :h string
echo system('git rev-parse --is-inside-work-tree') == "true\n"
" 1
You can remove the newline with a substitution:
system("git rev-parse --is-inside-work-tree")->substitute('\n','','') == 'true'
or compare against a regular expression:
system("git rev-parse --is-inside-work-tree") =~ 'true'
or get a list from the external command, with a single item because there is only one actual line in the output:
systemlist("git rev-parse --is-inside-work-tree")[0] == 'true'
See :help substitute(), help expr-=~, and :help systemlist().
Related
At the end of this bash tutorial video link ,Spencer Krum shows a neat hack: how to open a file in vim at the line number where an immediately preceding 'git grep -n' search string was located. It seemed neat, but his code does not work as described on two different linux boxes I tried it with. It just always opens a blank file. original code here
My steps:
First, I made sure to have git initialized and files inside the directory to grep for. For example, I had a somefile.txt with three lines of words:
its
a
mystery
Then I ran: git init;git add .; git commit
Then, modify your .bashrc file to redefine vim as shown below. Make sure to source the .bashrc file when complete: source ~/.bashrc
Finally, run the git grep -n command with a search term you know is in a file in your git directory that is your current working directory. Finally, run vim. It should open your file with the cursor at the search term line. But it doesn't: git grep -n mystery;vim
#Spencers Original
vim () {
last_command=$(history | tail -n 2 | head -n 1)
if [[ $last_command =~ 'git grep' ]] && [[ "$*" =~ :[0-9]+:$ ]]; then
line_number=$(echo $* | awk -F: '{print $(NF-1)}')
/usr/bin/vim +${line_number} ${*%:${line_number}:}
else
/usr/bin/vim "$#"
fi
}
To get the desired result, I had to simplify the regex in the second clause of the first if statement, and also create some temp variables to run additional eval logic on.
Below is my revised code:
#My revised version
vim () {
last_command=$(history | tail -n 2 | head -n 1)
rempws="${last_command#*" "}"
remtws="${rempws%*" "}"
file_name="$(eval $remtws | awk -F: '{print $(NF-2)}')"
line_number="$(eval $remtws | awk -F: '{print $(NF-1)}')"
if [[ $last_command =~ 'git grep' ]] && [[ $line_number =~ [0-9] ]]
then
/usr/bin/vim +${line_number} ${file_name}
else
/usr/bin/vim "$#"
fi
}
Is this related to a bash update since 2015? I don't think it's git related, as my git grep -n command does return a string in the form 'somefile.txt:3:mystery'. Everybody in the audience loved it, and it's still on github on the non-functioning form, so I am worried that I am missing something fundamental about bash.
Show me why I'm dumb.
Ok, I finally understood what this is about.
His code was never really meant to somehow access the output of the git grep command.
Instead, it's a realization that after a git grep you're likely to want to open one of the results.
But, in his workflow, he still relies on copy & paste of the git grep results into the Vim command-line.
The only difference is that, right after a git grep, you can pass Vim a filename with a line number separated by : rather than having to pass two separate arguments.
In his example, the result of git grep started with:
CHANGELOG.rst:75: ...
So, if at the next command you execute:
$ vim CHANGELOG.rst:75:
(Assuming you copied the last part from the git grep results.)
Then the bash function would trigger this command instead:
$ vim +75 CHANGELOG.rst
Which will open this file on line 75.
If you like the idea of this feature, a much cleaner way to implement that is to install and enable the bogado/file-line Vim plug-in, which implements support for that kind of filename + line number arguments in Vim itself.
(Also, there's really no good reason to only recognize the file:line syntax right after a git grep. If you want that behavior, it's better to always get it, not just sometimes. It should be consistent.)
An even better alternative is to use the quickfix feature of Vim, which was conceived for exactly this kind of situation. You can either set 'grepprg' manually, to invoke git grep with the appropriate arguments, or you can adopt a plug-in such as vim-fugitive, which implements a :Ggrep command that calls git grep and presents the results using the quickfix list.
As pointed out by #romainl, you might also want to look into git jump, which is a git command you can enable on your system to have git find interesting locations (such as git grep or git diff output) and have git itself open those results in Vim (using the quickfix list when appropriate.)
I want to set vim file search path to include git repository root (which can be found by git rev-parse --show-toplevel). I can't figure out how to append the output of this git command to "set path=.,,**" in .vimrc.
Thanks!
You can use this command:
let &path .= "," . system("git rev-parse --show-toplevel | tr -d '\\n'")
That said, I usually start Vim from the top-level directory of the project and never change the working directory so that's one less setting to worry about.
See :help system() and :help :let
" Add the git dir only once, and check for errors.
function! MoshGitPath()
let g:gitdir=substitute(system("git rev-parse --show-toplevel 2>&1 | grep -v fatal:"),'\n','','g')
if g:gitdir != '' && isdirectory(g:gitdir) && index(split(&path, ","),g:gitdir) < 0
exe "set path+=".g:gitdir."/*"
endif
endfunction
command! MoshGitPath :call MoshGitPath()
:MoshGitPath
I can't understand the following code in a bash.
set `pwd` ; mfix=$1
It actually get the run directory name.But I don't how does it work.
What is the set command mean?
From the doc for the set:
This builtin is so complicated that it deserves its own section. set
allows you to change the values of shell options and set the
positional parameters, or to display the names and values of shell
variables.
e.g.
set v1 v2 v3 ; echo $1
will print
v1
The comand inside backticks is called as "command substitution". From the docs:
Bash performs the expansion by executing command and replacing the
command substitution with the standard output of the command, with any
trailing newlines deleted.
In your example, it sets the 1st positional argument $1 to the value of the result of execution of command inside the backticks. (called as command substitution). The command is pwd what shows the current working directory.
Anyway, if the path to the directory contains an space, the $1 will get only the first part of the path., e.g.
$ pwd
/some/path with/space
$ set `pwd`
$ echo $1
/some/path
$echo $2
with/space
Finally the all above is strange design, because you can simply:
mfix=$(pwd) #old school: mfix=`pwd`
It is better to use the $(command) instead of the backticks.
This code in bash put the result of the command pwd in the variable mfix.
You can print the result of the mfix variable by running
echo $mfix
I am using an external command to populate my bash prompt, which is run each time PS1 is evaluated. However, I have a problem when this command outputs non-printable characters (like color escape codes).
Here is an example:
$ cat green_cheese.sh
#!/bin/bash
echo -e "\033[32mcheese\033[0m"
$ export PS1="\$(./green_cheese.sh) \$"
cheese $ # <- cheese is green!
cheese $ <now type really long command>
The canonical way of dealing with non-printing characters in the PS1 prompt is to enclose them in \[ and \] escape sequences. The problem is that if you do this from the external command those escapes are not parsed by the PS1 interpreter:
$ cat green_cheese.sh
#!/bin/bash
echo -e "\[\033[32m\]cheese\[\033[0m\]"
$ export PS1="\$(./green_cheese.sh) \$"
\[\]cheese\[\] $ # <- FAIL!
Is there a particular escape sequence I can use from the external command to achieve the desired result? Or is there a way I can manually tell the prompt how many characters to set the prompt width to?
Assume that I can print anything I like from the external command, and that this command can be quite intelligent (for example, counting characters in the output). I can also make the export PS1=... command as complicated as required. However, the escape codes for the colors must come from the external command.
Thanks in advance!
I couldn't tell you exactly why this works, but replace \[ and \] with the actual characters that bash generates from them in your prompt:
echo -e "\001\033[32m\002cheese\001\033[0m\002"
[I learned this from some Stack Overflow post that I cannot find now.]
If I had to guess, it's that bash replaces \[ and \] with the two ASCII characters before executing the command that's embedded in the prompt, so that by the time green_cheese.sh completes, it's too late for bash to process the wrappers correctly, and so they are treated literally. One way to avoid this is to use PROMPT_COMMAND to build your prompt dynamically, rather than embedding executable code in the value of PS1.
prompt_cmd () {
PS1="$(green_cheese.sh)"
PS1+=' \$ '
}
PROMPT_COMMAND=prompt_cmd
This way, the \[ and \] are added to PS1 when it is defined, not when it is evaluated, so you don't need to use \001 and \002 directly.
If you can't edit the code generating the string containing ANSI color / control codes, you can wrap them after the fact.
The following will enclose ANSI control sequences in ASCII SOH (^A) and STX (^B) which are equivalent to \[ and \] respectively:
function readline_ANSI_escape() {
if [[ $# -ge 1 ]]; then
echo "$*"
else
cat # Read string from STDIN
fi | \
perl -pe 's/(?:(?<!\x1)|(?<!\\\[))(\x1b\[[0-9;]*[mG])(?!\x2|\\\])/\x1\1\x2/g'
}
Use it like:
$ echo $'\e[0;1;31mRED' | readline_ANSI_escape
Or:
$ readline_ANSI_escape "$string"
As a bonus, running the function multiple times will not re-escape already escaped control codes.
I suspect that if you echo the value of $PS1 after your first example, you’ll find that its value is the word “cheese” in green. (At least, that’s what I see when I run your example.) At first glance, this is what you want — the word “cheese” in green! Except that what you really wanted was the word cheese preceded by the escape codes that produce green. What you did by using the -e flag for echo is produce a value with the escape codes already evaluated.
That happens to work for the specification of colors, but as you’ve found, it mangles the “non-printing sequence” markers into something the $PS1 interpreter doesn’t properly understand.
Fortunately, the solution is simple: drop the -e flag. echo will then leave the escape sequences untouched, and the $PS1 interpreter will Do The Right Thing™.
I'm trying to figure out how to work git filter-branch and I need help with some basic Linux scripting commands.
'git ls-files -s | sed "s-\t-&newsubdir/-" |
GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
git update-index --index-info &&
mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE' HEAD
Can anyone break this down for me and explain each part?
I'm most interested in the '|' notation, the && notation, and the sed command.
| connects stdout of the preceding command to stdin of the following command.
&& executes the following command if the return code of the preceding command is 0 (that is, the command succeeded).
The s command in sed is a substitution. It searches for a regex match for the first argument and replaces it with the second. The argument separator is traditionally /, but it will use the first character that follows, - in this case. The & in the replacement is replaced with the entire match.
"|" is the unix pipe command which connects the command on the left sides output to the command on the right side's input.
"&&" is the unix "and" command which will execute the command on its right if and only if the command on it's left completes successfully
"sed" is the unix "stream editor" a powerful editing tool which parses and edits it's input