Vim syntax for getting name of current file - bash

In Vim, I can echo the current filename using this command:
:echo #%
I found that information here: http://vim.wikia.com/wiki/Get_the_name_of_the_current_file
Can someone explain why the # symbol is necessary? If I enter the command without the # symbol, I get an error:
E15: Invalid expression: %
E15: Invalid expression: %
However, if I try to send the filename to a bang command as an argument, including the # sign appears as a regular character in the argument. Removing the # sign works. In other words, in my .bash_profile I have the following function:
test_func() {
echo $1
}
In Vim, I run:
:! test_func #% #outputs #path/to/my/file
:! test_func % #outputs path/to/my/file
What is the # symbol doing and why does it behave differently when sending the output to a bash function?

:echo takes a Vimscript expression, whereas :! takes and external command, which is a special case for a filename, which is accepted by :edit et al.
For external commands and filenames, there are special characters such as % and #, described under :help cmdline-special. This also includes this crucial sentence:
In Ex commands, at places where a file name can be used, the following
characters have a special meaning.
In contrast, :echo does not take a filename, but an expression. There are several ways to resolve the current filename; the most direct is via expand():
:echo expand('%')
Alternatively, as the current filename is also stored in a special register %, and registers are addressed via the # sigil:
:echo #%
The other way around
This also explains the frequent question of why :edit g:variable doesn't work as expected. Vim's evaluation rules are different than most programming languages. You need to use :execute in order to evaluate a variable (or expression); otherwise, it's taken literally; i.e. Vim uses the variable name itself as the argument.

I believe that is :h expr-register:
register expr-register #r
#r contents of register 'r'
The result is the contents of the named register, as a single string.
Newlines are inserted where required. To get the contents of the unnamed
register use #" or ##. See |registers| for an explanation of the available
registers.
When using the '=' register you get the expression itself, not what it
evaluates to. Use |eval()| to evaluate it.
As to why you don't need that for :! that is probably because of :h cmdline-special.
Ex special characters cmdline-special
Note: These are special characters in the executed command line. If you want
to insert special things while typing you can use the CTRL-R command. For
example, "%" stands for the current file name, while CTRL-R % inserts the
current file name right away. See |c_CTRL-R|.
Note: If you want to avoid the special characters in a Vim script you may want
to use |fnameescape()|.
In Ex commands, at places where a file name can be used, the following
characters have a special meaning. These can also be used in the expression
function expand() |expand()|.
% Is replaced with the current file name. :_% c_%

Related

Trouble understanding a bash command

I'm trying to set up a program and came across this line in a bash script. Could someone tell me what it does? I'm not very experienced with bash.
export PS1='\e[0;33mmyProject \e[0;32m\[\e]0;\u#\h: \w\a\]${debian_chroot:+($debian_chroot)}\u#\h:\w\$\e[0m '
Thank you very much!
This command does two things. It sets the title of the terminal window, and
sets the bash prompt.
export PS1='\e[0;33mmyProject \e[0;32m\[\e]0;\u#\h: \w\a\]${debian_chroot:+($debian_chroot)}\u#\h:\w\$\e[0m '
Piece by piece:
export PS1=
This sets the PS1 variable, which is contains the bash prompt.
\e[0;33m
\e is translated to the ESC character (ascii=0x1B), which is a Control Sequence Introducer, which signifies the beginning of an ANSI Escape Code. The m character at the end of the sequence indicates that the everything between [ and m is to be interpreted as a ;-separated list of SGR (Select Graphic Rendition) parameters (See here for more information). The 0 clears all previous text formatting, and the 33 sets the text color to yellow.
myProject
This just adds the string myProject to the bash prompt.
\e[0;32m
This clears all the previous text formatting (0) and sets the text color to green. (32)
\[ ... \]
\[ begins a sequence of non-printing characters which ends with \]. Everything between those two delimiters will not be visible in the prompt.
\e]0;\u#\h: \w\a
This sets the title of the terminal window to something like
username#hostname: /current/working/directory
The next bit:
${debian_chroot:+($debian_chroot)}
If the variable $debian_chroot has been defined, then this expression will evaluate to the value of $debian_chroot.
$debian_chroot is a variable that is set in /etc/bash.bashrc. This post explains it a lot better than I can.
\u#\h:\w\$\e[0m
\u evaluates to the username of the current user, \h evaluates to the name of the computer, and \w evaluates to the current working directory. \$ is just the character $. It needs to be escaped because in bash script, the character $ signifies that the following characters are the name of a variable. \e[0m reverts the text formatting back to default.
An image of what the prompt might look like in a terminal:
This is quite a complicated command you have here!
Let's break it down section by section.
export
This means that we are setting a variable to be used in other programs.
PS1=
The name of the variable is PS1.
\e
This is an escaped character. In bash (and most programming languages), Everything with a backslash before it is an escaped character. It is used for when you need to include a control character like a space, or the control key itself in a string. When it's escaped, bash treats it like it's part of the string, and not another control character.
[
This is the start of an array. It's very similar to an array in a C program.
;
This is an end character, it can mean several different things. Here, it's being used to define part of the array.
There is some other stuff here, but it's mostly just data in the array.
:
This is a NOT operand. It is used to determine the inverse of something.
${debian_chroot:+($debian_chroot)}
This is a variable. In bash, variables start with a $.
It is using the variable debian_chroot and adding it to itself if it's not null.
This command is just defining a variable, in this case an array containing information probably about a chroot with a debian install in it.

Bash script sourcing config file but can't use vars in arithmetic

This is killing me. I have a config file, "myconfig.cfg", with the following content:
SOME_VAR=2
echo "I LOVE THIS"
Then I have a script that I'm trying to run, that sources the config file in order to use the settings in there as variables. I can print them out fine, but when I try to put one into a numeric variable for use in something like a "seq " command, I get this weird "invalid arithmetic operator" error.
Here's the script:
#!/bin/bash
source ./myconfig.cfg
echo "SOME_VAR=${SOME_VAR}"
let someVarNum=${SOME_VAR}
echo "someVarNum=${someVarNum}"
And here's the output:
I LOVE THIS
SOME_VAR=2
")syntax error: invalid arithmetic operator (error token is "
someVarNum=
I've tried countless things that theoretically shouldn't make a difference, and, surprise, they don't. I simply can't figure it out. If I simply take the line "SOME_VAR=2" and put it directly into the script, everything's fine. I'm guessing I'll have to read in the config file line by line, split the strings by "=", and find+create the variables I want to use manually.
The error is precisely as indicated in a comment by #TomFenech. The first line (and possibly all the lines) in myconfig.cfg is terminated with a Windows CR-LF line ending. Bash considers CR to be an ordinary character (not whitespace), so it will set SOME_VAR to the two character string 2CR. (CR is the character with hex code 0x0D. You could see that if you display the file with a hex-dumper: hd myconfig.cfg.)
The let command performs arithmetic on numbers. It also considers the CR to be an ordinary character, but it is neither a digit nor an operator so it complains. Unfortunately, it does not make any attempt to sanitize the display of the character in the error message, so the carriage return is displayed between the two " symbols. Consequently, the end of the error message overwrites the beginning.
Don't create Unix files with a Windows text editor. Or use a utility like dos2unix to fix them once you copy them to the Unix machine.

What does "unterminated quoted string meets end of file" mean in MacVim?

I'm looking a way to compile Ruby code on OSX. I am using MacVim, and my code says:
puts "test"
I type rubydo %, and I get an error message SyntaxError: eval:1: unterminated quoted string meets end of file. What am I doing wrong?
Vim's rubydo command executes a command. You may have thought it was a filename (and used "%" as the parameter, i.e., the current buffer). The % is ruby's alternate string delimiter, and depending on how rubydo is implemented, the bare "%" could be mistaken for the beginning of a string.
The % Notation (Ruby Programming)
Vim documentation: if_ruby

jamplus: link command line too long for osx

I'm using jamplus to build a vendor's cross-platform project. On osx, the C tool's command line (fed via clang to ld) is too long.
Response files are the classic answer to command lines that are too long: jamplus states in the manual that one can generate them on the fly.
The example in the manual looks like this:
actions response C++
{
$(C++) ##(-filelist #($(2)))
}
Almost there! If I specifically blow out the C.Link command, like this:
actions response C.Link
{
"$(C.LINK)" $(LINKFLAGS) -o $(<[1]:C) -Wl,-filelist,#($(2:TC)) $(NEEDLIBS:TC) $(LINKLIBS:TC))
}
in my jamfile, I get the command line I need that passes through to the linker, but the response file isn't newline terminated, so link fails (osx ld requires newline-separated entries).
Is there a way to expand a jamplus list joined with newlines? I've tried using the join expansion $(LIST:TCJ=\n) without luck. $(LIST:TCJ=#(\n)) doesn't work either. If I can do this, the generated file would hopefully be correct.
If not, what jamplus code can I use to override the link command for clang, and generate the contents on the fly from a list? I'm looking for the least invasive way of handling this - ideally, modifying/overriding the tool directly, instead of adding new indirect targets wherever a link is required - since it's our vendor's codebase, as little edit as possible is desired.
The syntax you are looking for is:
newLine = "
" ;
actions response C.Link
{
"$(C.LINK)" $(LINKFLAGS) -o $(<[1]:C) -Wl,-filelist,#($(2:TCJ=$(newLine))) $(NEEDLIBS:TC) $(LINKLIBS:TC))
}
To be clear (I'm not sure how StackOverflow will format the above), the newLine variable should be defined by typing:
newLine = "" ;
And then placing the carat between the two quotes and hitting enter. You can use this same technique for certain other characters, i.e.
tab = " " ;
Again, start with newLine = "" and then place carat between the quotes and hit tab. In the above it is actually 4 spaces which is wrong, but hopefully you get the idea. Another useful one to have is:
dollar = "$" ;
The last one is useful as $ is used to specify variables typically, so having a dollar variable is useful when you actually want to specify a dollar literal. For what it is worth, the Jambase I am using (the one that ships with the JamPlus I am using), has this:
SPACE = " " ;
TAB = " " ;
NEWLINE = "
" ;
Around line 28...
I gave up on trying to use escaped newlines and other language-specific characters within string joins. Maybe there's an awesome way to do that, that was too thorny to discover.
Use a multi-step shell command with multiple temp files.
For jamplus (and maybe other jam variants), the section of the actions response {} between the curly braces becomes an inline shell script. And the response file syntax #(<value>) returns a filename that can be assigned within the shell script, with the contents set to <value>.
Thus, code like:
actions response C.Link
{
_RESP1=#($(2:TCJ=#)#$(NEEDLIBS:TCJ=#)#$(LINKLIBS:TCJ=#))
_RESP2=#()
perl -pe "s/[#]/\n/g" < $_RESP1 > $_RESP2
"$(C.LINK)" $(LINKFLAGS) -o $(<[1]:C) -Wl,-filelist,$_RESP2
}
creates a pair of temp files, assigned to shell variable names _RESP1 and _RESP2. File at path _RESP1 is assigned the contents of the expanded sequence joined with a # character. Search and replace is done with a perl one liner into _RESP2. And link proceeds as planned, and jamplus cleans up the intermediate files.
I wasn't able to do this with characters like :;\n, but # worked as long as it had no adjacent whitespace. Not completely satisfied, but moving on.

Makefile syntax $(A,B,C)?

Consider the following code:
$ANIMAL = COW PIG CHICKEN VAMPIRE
all:
#echo $(ANIMAL, F, >.txt)
I strove to find a section in GNU make manual that mentions the above syntax, but I couldn't find anything related to it. What does it print and how is the syntax structured for the functionality?
Added: When a line starts with "#--" what does it mean?
#-- $(GEN_ENV); ...
To answer your addition: In regular Makefiles (read: POSIX, GNU, ...)
a leading '#' supresses echoing of the command.
a leading '-' says to ignore a non-zero exit status
both can be combined, and repetitions are okay, so #---###-#---echo foo is the same as #-echo foo
This is called "macro modifiers". This is not a GNU make feature. Take a look at this chapter of OPUS make tutorial. The general syntax of these modifiers:
$(name,modifier[,modifier]...)
name is macro expanded, then each modifier is applied in succession to the elements of the expanded value.
Take a look then at the list of modifiers and it becomes clear that it forms a list of file names (truncates paths of each variable in ANIMAL) with .txt added. So, in your case it shoud output:
COW.txt PIG.txt CHICKEN.txt VAMPIRE.txt
PS
I looked through the reference mentioned above and don't think the first line ($ANIMAL = ) is correct since macro definition should start without $.
Based on your comments it seems you are actually using OpusMake, rather than GNU make. You can find more information about it on the Opus Software, Inc. website, and also in this handy reference guide. From those sources you can see that you have an example of a macro employing macro modifiers in its expansion.
Generally speaking $(FOO) is expanded to the unmodified value of the variable FOO, while $(FOO,mod1[,mod2[,...]]]) expands to the value of FOO, modified according to the modifiers you specify. Note that you can string together any number of modifiers, and they will be applied in left-to-right order.
There's a ton of possible modifiers, but your example specifically uses two:
The F modifier, which means "use just the final path component of each pathname in the variable value"
The >str modifier, which means "append the text str to each space-separated word in the value".
Here's a quick example:
FOO=abc/def ghi/jkl
BAR=$(FOO,F)
BAZ=$(FOO,>.txt)
BOO=$(FOO,F,>.txt)
BAR will have the value def jkl (ie, just the filename portion of each path).
BAZ will have the value abc/def.txt ghi/jkl.txt (ie, append .txt to each space-separated word in the value)
BOO will have the value def.txt jkl.txt (ie, first take just the filename portion of each path, then append .txt to each)

Resources