path setting for c++ include headers for vim - c++

My vim has path settings as shown below.
path=.,/usr/include,,
I think this is a default setting of 'path' I guess.
Because of this, g f opens c header files under the cursor.
But on C++ file C++ header files are not opened because the C++ header file location is not added to path variable of vim.
set path+=/usr/include/c++/4.6
I think that this setting on vimrc would be a solution.
But the problem is the actual directory location for C++ header file would be changed in every different linux distributions and g++ compiler versions.
How can I set path for c++ header files in a portable manner?
let g:gcpp_headers_path = system("g++ --version | grep g++ | awk '{print \"/usr/include/c++/\"$NF}'")
execute 'set path+=' . g:gcpp_headers_path
Now I am using this above:
This works with g++ environment. Not tested with other compilers.

If there's a limited number of locations, a simple conditional in ~/.vimrc will do:
if isdirectory('/usr/include/c++/4.6')
set path+=/usr/include/c++/4.6
elseif isdirectory(...
If you have a lot of different systems, and don't want to maintain all variations in a central place, you can move the system-dependent settings to a separate, local-only file, and invoke that from your ~/.vimrc, like this:
" Source system-specific .vimrc first.
if filereadable(expand('~/local/.vimrc'))
source ~/local/.vimrc
endif

I recently had the same problem, so here is my solution for documentation purposes:
1) I added the following to my .bashrc:
# add additional search paths to vim.
VIM_EXTPATHS="$HOME/.vim.extpaths"
if [ ! -e "$VIM_EXTPATHS" ] || [ "/usr/bin/cpp" -nt "$VIM_EXTPATHS" ]; then
echo | cpp -v 2>&1 | \
awk '/^#include </ { state=1 } /End of search list/ { state=0 } /^ / && state { print "set path+=" substr($0, 2) "/**2" }' > $VIM_EXTPATHS
fi
2) I added the following to my .vimrc:
" add extra paths.
let s:extpaths=expand("$HOME/.vim.extpaths")
if filereadable(s:extpaths)
execute "source ".s:extpaths
endif
On my system, the contents of the .vim.extpaths file are as follows:
set path+=/usr/lib/gcc/x86_64-linux-gnu/8/include/**2
set path+=/usr/local/include/**2
set path+=/usr/lib/gcc/x86_64-linux-gnu/8/include-fixed/**2
set path+=/usr/include/x86_64-linux-gnu/**2
set path+=/usr/include/**2
The **2 means that ViM will search two directories deep inside these directories. Now gf will find all the C++ headers I need. If you increase the depth, searches will take a lot more time, so don't set this number too high.
#note: for #include <chrono>, ViM will go to /usr/include/boost/chrono, which, funny enough, is a directory. I wonder why go file will open a directory, maybe this should be reported as a bug. To get to the correct chrono header you have to type 2gf.

The following Vimscript code, intended for a .vimrc file, updates path to include the search paths used by the preprocessor.
if executable('gcc')
let s:expr = 'gcc -Wp,-v -x c++ - -fsyntax-only 2>&1 | grep "^ " | sed "s/^ //"'
let s:lines = systemlist(s:expr)
for s:line in s:lines
execute 'set path+=' . fnameescape(s:line)
endfor
endif
I have similar code in my .vimrc, but with additional special-case handling.

There are specific environment variables for the compiler to examine. If you are using gcc/g++ in a linux/Unix environment, then the variables are C_INCLUDE_PATH and CPLUS_INCLUDE_PATH. If you are using bash/sh then use export VARIABLE=value or if you are using csh/tcsh then use setenv VARIABLE value or if you are using some other shell then you will need to look that up. In these examples VARIABLE is either C_INCLUDE_PATH and CPLUS_INCLUDE_PATH. I hope this helps.

Related

Is there a way for changing text file names in a folder using C++

I am working with a bunch of txt files(thousands) on my project. Each txt file has 'csv' information on it. The problem is that each txt file has a random name and I cannot create a code for loading them in my project due to it. So, I want to rename them in a particular pattern to make easier the loading of the files in my work. I will use C++ for accomplish this task.
I put all the txt files in a folder but I cannot see a way of renaming them using C++. How can I do this? is there a way to do it? Can someone help me?
You can use std::filesystem::directory_iterator and std::filesystem::rename (c++17), as documented here.
Disclaimer
This answer validity is based on a comment where the author precised they were not bound to the C++ language (it may be worth editing the question, the C++ tag, and the OS). This solution may work for UNIX systems supporting bash, that is most Linux distributions and all releases of Apple's macOS prior to macOS Catalina (correct me if I'm wrong).
Bash command line
Using the following bash command should rename all the files in a folder with increasing numbers, that is:
toto.csv -> 1.csv
titi.csv -> 2.csv etc
It assumes the ordering is not important.
a=1; for i in *; do mv -n "$i" "$a.csv" ; let "a +=1"; done
To test it, you can prepare a test folder by opening a terminal and typing:
mkdir test
cd test
touch toto.csv titi.csv tata.csv
ls
Output:
tata.csv titi.csv toto.csv
Then you can run the following command:
a=1; for i in *; do mv -n "$i" "$a.csv" ; let "a +=1"; done
ls
Output:
1.csv 2.csv 3.csv
Explication:
a=1 declare a variable
for i in *; begin to iterate over all files in the folder
do mv will move (rename) a file of the list (that is, the variable $i) to a new name called a.csv
and we increment the counter a, and close the loop.
the option -n will make sure no file gets overwritten by the command mv
I assumed there was no specific criterion to rename the files. If there is a specific structure (pattern) in the renaming, the bash command can probably accommodate it, but the question should then give more details about these requirements :)

Regex to add an extension to a directory full of files

I am new to regular expressions.
I have many irregularly numbered ascii files with no extension: g000554, g000556, g000558, g000561, g000563 ... g001979 etc
I would like to type a regex at the terminal (or in a short script) to add a .dat to all of these files.
So I would like to change them to become: g000554.dat, g000556.dat, g000558.dat, g000561.dat, g000563.dat ... g001979.dat etc
p.s. Sorry I should have provided more info: by terminal I meant a mac terminal and I cannot use the 'rename' command.
I think you're using a linux system. So i provide a bash solution. It works only if your files starts with g and there is no other files in that directory except the files you want to rename.
for i in g*; do mv "$i" "$i.dat"; done
The below would add .dat extension to all the files present in the current directory,
for i in *; do mv "$i" "$i.dat"; done

Generate CTAGS for libstdc++ (from current GCC)

I know YoucompleteMe on base of LLVM, but I want to use OmniCppComplete. This works nice, if I use the modified headers for C++. This modified headers are outdated and doesn't contain anything from C++11.
If noticed that I can modifiy my headers myself e.g.:
$ find . -name '*.h' | xargs sed -i 's/__STL_BEGIN_NAMESPACE/namespace std {/'
$ find . -name '*.h' | xargs sed -i 's/__STL_END_NAMESPACE/}/'
Or use this setting:
let OmniCpp_DefaultNamespaces = ["std", "_GLIBCXX_STD"]
Both doesn't work and of course most headers doesn't have and any file extensions. I've already tried to workaround this by using a list of files. How can I create working CTAGS on base of my current GCC (e.g. /usr/include/c++/...)? What is the common way?
Thank you
This is what I got, if I try to complete something from LIBSTD++:
std::fs
Omni completion (^O^N^P) Back at original
Ctrl+x, Ctrl+o
Omni completion (^O^N^P) Pattern not found
Finally I've written despairingly an email to the author of the modified headers for the LIBSTDC++ (GCC). He answered me promptly (thanks!):
Requirements:
Install vim and vim-omnicppcomplete and ctags (dependency of vim-omnicppcomplete).
Solution:
$ cp -R /usr/include/c++/$GCC_VERSION ~/.vim/cpp_src
# it is not necessary to rename headers without an extension
# replace the "namespace std _GLIBCXX_VISIBILITY(default)" with "namespace std"
$ find . -type f | xargs sed -i 's/namespace std _GLIBCXX_VISIBILITY(default)/namespace std/'
$ ctags -f cpp_tags -R --c++-kinds=+p --fields=+iaS --extra=+q --language-force=C++ -I _GLIBCXX_NOEXCEPT cpp_src
Edit your ~/.vimrc:
" configure tags - add additional tags here or comment out not-used ones
set tags+=~/.vim/cpp_tags
" build tags of your own project with Ctrl-F12
map <C-F12> :!ctags -R --sort=yes --c++-kinds=+p --fields=+iaS --extra=+q -I _GLIBCXX_NOEXCEPT .<CR>
" OmniCppComplete
let OmniCpp_NamespaceSearch = 1
let OmniCpp_GlobalScopeSearch = 1
let OmniCpp_ShowAccess = 1
let OmniCpp_ShowPrototypeInAbbr = 1 " show function parameters
let OmniCpp_MayCompleteDot = 1 " autocomplete after .
let OmniCpp_MayCompleteArrow = 1 " autocomplete after ->
let OmniCpp_MayCompleteScope = 1 " autocomplete after ::
" also necessary for fixing LIBSTDC++ releated stuff
let OmniCpp_DefaultNamespaces = ["std", "_GLIBCXX_STD"]
" automatically open and close the popup menu / preview window
au CursorMovedI,InsertLeave * if pumvisible() == 0|silent! pclose|endif
set completeopt=menuone,menu,longest,preview
Autocompletion for LIBSTDC++ should now work within vim!
Manuall autocomplete with Ctrl+x -> Ctrl+o.
If you still have trouble with autocomplete, you maybe find a solution in the documentation (see FAQ 7).
Bye
After try hard to search how to create c++-specific tags file using ctags, finally I made desirable progress. Need to say, ctags indeed is a little hard to use, powerful though.
First to emphasize, DONOT ignore -I option (see here for more option info) provided by ctags. It's pretty important for you to see more symbols in the tags file. Simply speaking, ctags cannot process some irregular syntactic statements, for example, prefixed or suffixed with C/C++ macros. If many functions are prefixed or suffixed with some kind of macros, ctags may be very likely to drop it. In the end, you cannot see them when coding.
Here's a way I use to find such macros as more as possible from C++ standard header path, /usr/include/c++/4.9.3 for example, and add them to -I option.
find /usr/include/c++/ -type f -exec grep '_GLIBCXX_' {} \; | grep -v -E '^[#if|#end]' | sort -u > glibcxx.log
After the command, you'll find several macros used in C++ 4.9.3 source files, then choose some of them to be ignored by ctags.
My final command to generate c++ tags file is this:
ctags -R --languages=c++ --langmap=c++:+.tcc. --c++-kinds=+p --fields=+iaS --extra=+qf -I "_GLIBCXX_NOEXCEPT _GLIBCXX_USE_NOEXCEPT _GLIBCXX_NOTHROW _GLIBCXX_USE_CONSTEXPR _GLIBCXX_BEGIN_NAMESPACE_CONTAINER _GLIBCXX_END_NAMESPACE_CONTAINER _GLIBCXX_CONSTEXPR _GLIBCXX_NAMESPACE_LDBL _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_END_NAMESPACE_VERSION _GLIBCXX_VISIBILITY+" -f gcc-4.9.3.tags /usr/include/c++/4.9.3/
Caveat
DONOT forget to write . sign following word tcc, it means match those files without explicit extension name such as vector,set
DONOT forget to write + sign following word VISIBILITY, it means match std _GLIBCXX_VISIBILITY(**)
DONOT forget to write + sign followed by .tcc, it means append the denoted extension to current map of the langugae, otherwise replace the map
I actually use OmniCppComplete too, and have been happily using a C++ only tags file (amongst others. I break my tags files up into smaller pieces, like C++, boost, X11, etc.) for quite a while. Here's the solution I use for generating that tags file on Ubuntu 14.04:
ctags -f cpp_tags --c-kinds=cdefgmstuv --c++-kinds=cdefgmstuv --fields=+iaSmKz --extra=+q --langmap=c++:+.tcc. --languages=c,c++ -I "_GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_END_NAMESPACE_VERSION _GLIBCXX_VISIBILITY+" -n $INC_DIR/* /usr/include/$CPP_TARGET/c++/$CPP_VERSION/bits/* /usr/include/$CPP_TARGET/c++/$CPP_VERSION/ext/* $INC_DIR/bits/* $INC_DIR/ext $SYSTEM/* $SYSTEM2/*
Where:
CPP_VERSION=4.8
INC_DIR=/usr/include/c++/$CPP_VERSION
CPP_TARGET=x86_64-linux-gnu
SYSTEM=/usr/lib/gcc/x86_64-linux-gnu/4.8/include
SYSTEM2=/usr/lib/gcc/x86_64-linux-gnu/4.8/include-fixed
Please note that the real trick to getting most of the tags generated is the -I option! It may need to be tweaked. Of course, the --c-kinds/c++-kinds and fields options can be adjusted as well.
The final piece is adding:
tags+=cpp_tags
to your .vimrc file to allow the tags to be seen.
All of this requires NO MODIFICATIONS to the headers. If you use a different C++ library, chances are you'll need to fiddle with the -I option to get the tags to show up properly (or even at all).
Now that I think about it, I should probably post this information in the Vim Wiki also.
Your second part about let OmniCpp_DefaultNamespaces can stand some improvement. Try let OmniCpp_DefaultNamespaces = ["std", "_GLIBCXX_STD", "_GLIBCXX_STD_A", "_GLIBCXX_STD_C"]. That's what I use and should allow for more items to be found.
Finally, don't forget about using Vim's CTRL-p to complete the std::fs. It's quite powerful... and no tags file required!

auto fold for C++ sources and headers

I have heard that Vim has a built-in support of folding for the files written in various programming languages. Particularly I'm interested in cpp, h, hpp files. I would like to achieve such a behavior of Vim when all the function definitions are folded by default in every newly opened source file. I don't want to create every fold manually with zF.
I added the following lines to the end of ~/.vimrc file (which was inherited from spf13-vim distribution):
set foldenable
autocmd FileType c,cpp,h,hpp setlocal foldmethod=syntax
Unfortunately that did not resulted to the desired behaviour. All the files look just the same, and my attempt to hide the function with zc combo leads to error:
E490: No fold found
I would be glad if someone could explain how to enable folding by default in Vim 7.4.
UPD: The code above works good, but there is still an issue with the recently opened files. Say we work on the project called 'sc-client-server' and we've just appended those two lines to ~/.vimrc and now ready to get back to the last edited file:
$ vim ~/.vimrc //Modify config
$ reboot
$ vim ~/progs/sc-client-server/src/st.cpp //No fold found. BUT:
$ cp ~/progs/sc-client-server/src/st.cpp /tmp
$ vim /tmp/st.cpp //Auto fold works fine. OR:
$ cd ~/progs/sc-client-server/src/ && mv src source
$ vim ~/progs/sc-client-server/source/st.cpp //Auto fold works fine.
Is there any kind of cache or memory inside of Vim that prevents the desired file representation?
Answer
Remove all (or specific for you) files from ~/.vimviews folder.
To the off-topic voters https://meta.stackexchange.com/questions/25925/vim-questions-do-they-belong-to-stack-overflow-or-super-user/25930#25930?newreg=00a4918bba924cfa8b1d6a3e82061672

Automatically fix filename cases in C++ codebase?

I am porting a C++ codebase which was developed on a Windows platform to Linux/GCC. It seems that the author didn't care for the case of filenames, so he used
#include "somefile.h"
instead of
#include "SomeFile.h"
to include the file which is actually called "SomeFile.h". I was wondering if there is any tool out there to automatically fix these includes? The files are all in one directory, so it would be easy for the tool to find the correct names.
EDIT: Before doing anything note that I'm assuming you either have copies of the files off ot the side or preferably that you have a baseline version in source control should you need to roll back for any reason.
You should be able to do this with sed: Something like sed -i 's/somefile\.h/SomeFile.H/I' *.[Ch]
This means take a case-insensitive somefile (trailing /I) and do an in-place (same file) replacement (-i) with the other text, SomeFile.H.
You can even do it in a loop (totally untested):
for file in *.[Ch]
do
sed -i "s/$file/$file/I" *.[Ch]
done
I should note that although I don't believe this applies to you, Solaris sed doesn't support -i and you'd have to install GNU sed or redirect to a file and rename.
Forgive my, I'm away from my linux environment right now so I can't test this myself, but I can tell you what utilities you would need to use to do it.
Open a terminal and use cd to navigate to the correct directory.
cd ~/project
Get a list of all of the .h files you need. You should be able to accomplish this with the shell's wildcard expansion without any effort.
ls include/*.h libs/include/*.h
Get a list of all of the files in the entire project (.c, .cpp, .h, .whatever), anything that can #include "header.h". Again, wildcard expansion.
ls include/*.h libs/include/*.h *.cpp libs/*.cpp
Iterate over each file in the project with a for loop
for f in ... # wildcard file list
do
echo "Looking in $f"
done
Iterate over each header file with a for loop
for h in ... # wildcard header list
do
echo "Looking for $h"
done
For each header in each project file, use sed to search for #include "headerfilename.h", and replace with #include "HeaderFileName.h" or whatever the correct case is.
Warning: Untested and probably dangerous: This stuff is a place to start and should be thoroughly tested before use.
h_escaped=$(echo $h | sed -e 's/\([[\/.*]\|\]\)/\\&/g') # escapes characters in file name
argument="(^\s*\#include\s*\")$h_escaped(\"\s*\$)" # I think this is right
sed -i -e "s/$argument/\$1$h\$2/gip"`
Yes, I know it looks awful.
Things to consider:
Rather than going straight to running this on your production codebase, test it thoroughly first.
sed can eat files like a VCR can eat tapes.
Make a backup.
Make another backup.
This is an O(N^2) operation involving hard disk access, and if your project is large it will run slowly. If your project is not gigantic, don't bother, but if it is, consider doing something to pipe sed's output to other seds.
Your search should be case insensitive: it should match #include, #INCLUDE, #iNcLuDe, and any combination of case present in the existing header filename, as well as any amount of whitespace between the include and the header. Bonus points if you preserve whitespace.
Use Notepad++ to do a 'Find in Files' and replace.
From toolbar:
Search - Find in Files.
Then complete the 'Find what' and 'Replace with'.