Run makefile if it exists, otherwise run extension specific command with vimscript - makefile

I want to map F9 to run the makefile in the current or parent directories, and if no makefile is found, run something based on the file extension.
I tried doing this:
function! Runf9()
if filereadable("./Makefile")
make
elseif (&filetype == "tex")
execute("!pdflatex " + bufname("%"))
endif
endfunction
nmap <silent> <F9> :call Runf9()<CR>
But this only works for makefiles in the current directory, I don't know how to search for them in the parent directories, it also does not work for .tex files when there is no Makefile.

If the + in the line with execute is exchanged with a . it works.

You can do (both up- and downward-) file searches via the findfile() function.
As you've already found out, string concatenation has to be done with ., not with +, which is for numerical addition only.

Related

How to remove a file named '.'?

Ok so i did something very stupid (copying a file and renaming it '.') since I thought it would just copy it as .uniprot_sprot.fasta.gz.icloud.
cp /path/.uniprot_sprot.fasta.gz.icloud .
and now I don't know how to remove it from current directory as it would be removing '.' itself.
What can I do?
This doesn't work. It says: No such file or directory
rm .uniprot_sprot.fasta.gz.icloud
On the other hand:
ls -a
gives this:
.
..
uniprot_sprot.fasta.gz.icloud
You have not copied a file and renamed it . (at any rate if you're running a sane *nix). Instead you have copied the file to the current directory with the name of the original file. (If you pass a directory to cp as the destination, files will be placed in that directory. . is the current directory, so this is all that has happened.) If you want to remove it you can just rm uniprot_sprot.fasta.gx.iscloud or explicitly rm ./uniprot_sprot.fasta.gx.iscloud. What you have tried to do is to remove a file whose name starts with ., which is a different thing.
Edit: I was unaware when I wrote this, but this is in fact simply down to . existing as a real, regular hardlink. At syscall level you can create a file whose name contains anything except / and \x00 (yep, including \n), assuming your filesystem allows it. However, the links . and .. are already present and thus unavailable as a file name. #thatotherguy links to the kernel source for the rmdir syscall, showing that in modern Linux at least it is the kernel itself which ultimately prevents you from deleting . and ...
Note that in bash, . at the beginning of a line by itself means source.
See this question on unix.se and its linked dupe for more information on the filename problem.

Print all ongoing targets in Makefile

I have written a makefile which has pretty complicated dependency, and executes with multiple jobs in parallel (make -j100 for example). I am trying to find a way to print all the current running target names. Any idea? Thanks in advance.
If what you want is a kind of command that you can run from time to time while make is running, and that shows all currently executing recipes, you could slightly modify your recipes such that they first create a temporary file with the name of the target, do whatever they are supposed to do and delete the temporary file. Listing these temporary files anytime will then show you the currently executing recipes.
Example if all targets are located under the directory from which make is called (or sub-directories of it):
TAGSDIR := .tags
MKTAG = mkdir -p "$(TAGSDIR)/$(#D)" && touch "$(TAGSDIR)/$#"
RMTAG = rm -f "$(TAGSDIR)/$#"
<target>: <prerequisites>
#$(MKTAG)
<regular recipe>
#$(RMTAG)
And list all files under .tags to get the names of all currently running recipes. Example with find:
find .tags -type f -printf '%P\n'
You could even encapsulate this in an infinite loop and refresh the list e.g. every second:
while true; do clear; find -type f -printf '%P\n'; sleep 1; done
EDIT
Andreas noticed that this works only if the targets are all located under the directory from which make is called. If a target is ../foobar, for instance, the temporary tag file would be .tags/../foobar, which is not what we want.
Andreas suggests to substitute .. with \.\. and / with \/. We could maybe find a way to do something like this under GNU/Linux and macOS (but not exactly, you cannot have a slash in a file name) but there could still be other issues under Windows (C:, backslashes...).
We could also store the name of the target in a text file and use mktemp or an equivalent to generate the text file with a unique name. But we would then need a way to propagate this unique name from MKTAG to RMTAG. This is doable with a shell variable and a one-line recipe (or the .ONESHELL special target) but not very nice.
As you use GNU make we could also use abspath and create temporary files named $(TAGSDIR)/$(abspath $#) but I do not know what abspath does under Windows with drive letters, nor do I know if you can name a file something\c:\something under Windows...
So, if your targets are not all located under the directory from which make is called, the best is to use another solution.

Using Windows Command Line with Python Subprocess Module

So basically I've got the worst situation possible on Windows... A path with spaces on a drive other than C:/
I'm trying to run the following:
print(subprocess.check_call("cd d: && d: && " + '"' + dir_name + '"', shell=True))
Where dir_name is the name of the directory plus the name of the executable file. The way I get dir_name is as follows:
dir_path = os.path.dirname(os.path.realpath(__file__))
dir_name = (dir_path.replace("\\","/") + "/bowtie2-2.3.4-mingw-x86_64/bowtie2-build").replace(" ", "\\ ")
I've also tried a few different variants of dir_name:
dir_path + "/bowtie2-2.3.4-mingw-x86_64/bowtie2-build"
dir_path.replace("\\","/")+"/bowtie2-2.3.4-mingw-x86_64/bowtie2-build"
I've tried it with and without quotes surrounding the whole thing, I've tried it with and without the shell option, I've tried it in cmd.exe and basically every time I get something along the lines of:
The system cannot find the path specified.
The full path is essentially:
D:/My Documents/2018 Documents/Class Name/Assignment Name/Subfile/ProgramName
With the variants I've tried being:
D://My Documents//2018 Documents//Class Name//Assignment Name//Subfile//ProgramName
D:/My\ Documents/2018\ Documents/Class\ Name/Assignment\ Name/Subfile/ProgramName
D://My\ Documents//2018\ Documents//Class\ Name/Assignment\ Name//Subfile//ProgramName
"D:/My Documents/2018 Documents/Class Name/Assignment Name/Subfile/ProgramName"
"D:/My\ Documents/2018\ Documents/Class\ Name/Assignment\ Name/Subfile/ProgramName"
"D://My\ Documents//2018\ Documents//Class\ Name//Assignment\ Name//Subfile//ProgramName"
I'm up for anything at this point, thank you so much in advance!
EDIT #1:
Based on comments, I should add that I'm trying to run bowtie2-build which is an extensionless program in the Bowtie package. It takes two command-line arguments, an input file and an output file name.

What does slash dot refer to in a file path?

I'm trying to install a grunt template on my computer but I'm having issues. I realized that perhaps something different is happening because of the path given by the Grunt docs, which is
%USERPROFILE%\.grunt-init\
What does that . mean before grunt-init?
I've tried to do the whole import manually but it also isn't working
git clone https://github.com/gruntjs/grunt-init-gruntfile.git "C:\Users\Imray\AppData\Roaming\npm\gru
nt-init\"
I get a message:
fatal: could not create work tree dir 'C:\Users\Imray\AppData\Roaming\npm\.grunt-init"'.: Invalid argument
Does it have to do with this /.? What does it mean?
The \ (that's a backslash, not a slash) is a directory delimiter. The . is simply part of the directory name.
.grunt-init and grunt-init are two distinct names, both perfectly valid.
On Unix-like systems, file and directory names starting with . are hidden by default, which is why you'll often see such names for things like configuration files.
The . is part of a directory name. Filenames can contain . . The \ is a separator between directory names.
Typically, files or directories starting with . are considered "hidden" and/or used for storing metadata. In particular, shell wildcard expansion skips over files that start with ..
For example if you wrote ls -d * then it would not show any files or directories beginning with . (including . and .., the current and parent directories).
Linux hides files and directories whose names begin with dot, unless you use the a (for "all") option when listing directory contents. If this convention is not followed on Windows, your example is probably just a carryover.
It may well be something behind the scenes (later) expects that name to match exactly. While I like things, installers, for example, to just do what I said, I realize that keeping default value is the most tested path.
Directories starting with a dot are invisible by default on xNIX systems. Typically used for configurations files and similar in a users home directory.
\ before " has a special meaning on windows, the error is because windows won't let you create a file containing " as part of its name.

Unexpected bash autocompletion behavior within a symbolic link loop

I have the following directory structure:
base/
dir/
subdir/
link -> ../dir
Now if I cd to dir/link and type:
cd ../subd[tab]
I get:
cd ../subdir[space]
I would understand if autocomplete fails (because it would canonize the path and look into base/ and not dir/).
I would also understand if it autocompletes to cd ../subdir/ with the ending / (because it would interpret .. as go up one level and search into dir/).
But I do not understand the actual behaviour that is somewhere between the two. Ideally I would like bash to behave like 2. (autocomplete to cd ../subdir/). I am using fedora 14, bash version 4.1.7(1). Any idea how to accomplish this ?
UPDATE: The program with which you can customize auto-completion is called complete.
You can find some good basic examples here: More on Using the Bash Complete Command
Using function and script names as per the above link, here is a script which appends the / to a symbolic link to a directory... It is just a rough sample, but it shows it can be done (I haven't tried it with the cd builtin...
Associate the function _mycomplete_ with executable myfoo
complete -F _mycomplete_ myfoo
The function to go in ~/.bashrc
function _mycomplete_()
{
local cmd="${1##*/}"
local word=${COMP_WORDS[COMP_CWORD]}
local line=${COMP_LINE}
local xpat='!*.foo'
COMPREPLY=($(compgen -f -X "$xpat" -- "${word}"))
if ((${#COMPREPLY[#]}==1)) ;then
[[ -h $COMPREPLY ]] && COMPREPLY="$COMPREPLY/"
fi
}
Original answer:
At the command-line, the main indicator of a auto-expansion to a symbolic link is shown on the last line of the following table, ie. a name expands but without the final /.
on pressing TAB on pressing TAB (again)
what happens? meaning what happens?
=================== ======================= ====================================
Nothing is appended 1=> Multiple sub-dirs exist => A list of possibilities is presented
2=> No sub-directory exists => Nothing is appended (again)
Expands to end in / => A uniquely matching dir => ...as per first column (repeat)
Expands text only => Current name is a link => Expands to end in /
In your example, if you have already primed the command-line to the full name, ie. cd link then the indicator is not obvious. Also you won't know it is a symbolic link via the list of possibilities.
To be able to cd to the link's target, you can use cd -P link, or set -P; cd link
After digging the source code a bit, it looks like this is a bit complicated. The actual problem is a mix between bash allowing symlinks inside the working directory (see pwd -L and pwd -P) and readline not able to determine the type of a match if it is not in a physical directory
In readline/complete.c:1694
s = (nontrivial_match && rl_completion_mark_symlink_dirs == 0)
? LSTAT (filename, &finfo)
: stat (filename, &finfo);
stat() fails since ../ is understood as relative to the physical path and not the logical path. readline fails to determine this is a directory and therefore does not append the final '/'.
A very similar problem is described here
So I guess I can live with the existing behaviour for now...
I was having the exact same problem in Ubuntu. Autocompletion was working like in your example #2, but started working as you describe at some point. I purged and reinstalled the package bash-completion, and now everything seems back to normal. Do not uninstall bash! Only bash-autocompletion.
Edit
look at this:
https://bbs.archlinux.org/viewtopic.php?id=113158

Resources