Vim autocomplete from ctags for system headers only works when popup is triggered manually - c

On OS X, I generated a set of ctags for the system includes using the following command:
ctags -f c -h ".h" -R --c-kinds=+p --fields=+iaS --extra=+q /usr/include
This was run inside of a ~/.vim/ctags/ directory, where I put all of the ctags I generate for system-wide header files (I also have stuff for ROS and CPP that I load conditionally, but that's neither here nor there).
Anyway. The ctags file is set correctly in my .vimrc, and vim can definitely see the ctags, but for some reason the autocomplete popup will only display results from #included header files if I write out the entire symbol and then start backspacing. As an example, if I #include <string.h> in a project, and then I want to call strlen(), and I start to type str in to the active vim buffer, I will only get results for symbols that are currently in the vim buffer. But, if I type out strlen and then start backspacing one or two characters and hit <C-n>, the popup menu will be populated with matches from any other included header files.
EDIT: Turns out, if I just hit "s" then <C-n>, it works as well. So the problem seems to be that it only works if the popup menu is launched manually. Which makes me think that it's a plugin problem (see below)
Additional information:
completeopt is set to completeopt=menuone,menu,preview,longest
I have OmniCppComplete, which I suppose could be interfering with the behavior. It is currently not being conditionally loaded for C++ files only. If you want me to edit and post my OmniCppComplete settings from my .vimrc, just ask.
I also have AutoComplPop installed, but I haven't done anything to configure it, so it's running with its default settings. Haven't really researched the plugin, so no idea if some of it's behavior could be interfering with the results.
I have AutoTag and TagBar installed, but those should only be fiddling with the current directory's local tagfile.
I'm honestly pretty new to Vim, and I just have no idea where to start debugging this issue, whether it be with a random plugin or with my .vimrc settings.

Vim has many specific completion mechanisms.
<C-n> and <C-p> use many sources defined by the complete option. By default, they will provide completion using the current and all loaded and unloaded buffers, tags and included files. While you can usually get quite useful suggestions with these, it is a bit of a "catch-all" solution: it is not reliable at all if you work on reasonably large projects.
<C-x><C-]> uses only tags so it may be a little more useful to you.
And there are many more, see :h ins-completion.
Omni completion is smarter: it typically runs a custom filetype-specific script that tries hard to provide meaningful completion. It is triggered by <C-x><C-o> and you can read about it in :h ft-c-omni. Omni completion is often a better choice when working with code.
Because you have two overlaping "auto"-completion plugins it's hard to say what completion mechanism is at work. You should disable those plugins and play around with the different completion mechanisms available to you.

I have not mastered this yet, but I do think the following observation may be of help.
Vim's default auto complete which can be quite noisy, often gets in the way of what you call with <C-x><C-o>. Specifically, I found myself calling up my tags based completions with <C-x><C-o> only to have them replaced with continued typing with Vim's default suggestions using my open buffers.
The suggestion of shutting off one of the plugins makes sense. In my case the key was how to shut down Vim's default behavior. I have seen several people (and to which I now include myself), set the length of the expression to a high number before triggering Vim's default. For me that is:
let g:deoplete#auto_complete_start_length = 99
... this way you eliminate the default layer of completions that comes and goes regardless of the commands you intended to inform your work.
This still feels like a hack but it helps keep my work focused on the tag-based completions.
FYI: I use NVIM on a Mac.

Related

Is there a way to get help for some C functions inside of vim/Neovim?

This question may be a little off topic. But I was wondering if there was a way for me to look at the descriptions of C functions using vim or neovim. Is it possible to look at their documentations by doing something like :help? This would really be helpful since I wouldn't need to lookup to my browser everytime.
I am unclear about these things:
Can :help be my friend here ?
Can I use LSPs to do something like this ?
I am using latest Neovim inside Ubunutu 20.04 in WSL. Is this helpful somehow ?
By pressing K, the keyword under the cursor is looked up using a configured keyword lookup program, the default being man. This works pretty much out of the box for the C standard library.
For C++, you might want to look at something like cppman.
Well yes, you can get the description of C functions by using a LSP (language server plugin)! Here is an image of me using clangd as my LSP:
You'd "just" need to install the LSP and start it. I don't know how familiar you're with neovim, but just in case if you don't know how to install a plugin or to be more specifique: If you don't know how you can install a LSP server, then you can do the following:
There're plenty videos how to set up a LSP-Server for your language. Here's an example.
If you don't want to set up on your own, you can pick up one of the preconfigured neovim setups (some of my friends are recommending lunarvim)
But yeah, that's it. If you have any further questions feel free to ask them in the comments.
Happy vimming c(^-^)c
Let's explain how "K" command works in more detail.
You can run external commands by prefixing them with :! command. So running man tool is as easy as
:!man <C-R><C-W>
Here <C-R><C-W> is a special key combination used to put word under cursor from text buffer down to command line.
Same for showing Vim's built-in help page
:help <C-R><C-W>
As it feels tedious to type that, Vim also defines K Normal mode command that does pretty much the same thing. Except the tool name is taken from value of an option named "keywordprg".
So doing set keywordprg=man (default for *nix systems) makes K to invoke !man tool; while set keywordprg=:help is for bultin help.
Also, the option :h 'keywordprg' is made global or local-to-buffer, so any Vim buffer is able to overwrite global setting. For example, this is already done by standard runtime for "vim" and "help" buffers, so they call ":help" instead of "man".
The problem with :!man command is that it shows "black console". It'd be nice if we could capture man's output and open it inside Vim just like a builtin help page. Then we could also apply some pretty highlighting, assign key macros and all such. This is a pretty common trick and it is already done by a standard plugin shipped with Vim/Neovim.
A command that the plugin provides is called :Man, so you can open :Man man instead of :!man man, for example. The plugin is preactivated in Neovim; for Vim you still need to source one file manually. So to make use of this plugin you'll need something like this
set keywordprg=:Man
if !has("nvim")
source $VIMRUNTIME/ftplugin/man.vim
endif
The previous answer recommending cppman is the way to go. There is no need to install a bulky language server just for the purpose of having the hover functionality. However, make sure you're caching the man pages via cppman -c. Otherwise, there will be a noticeable delay since cppman is fetching the page from cppreference.com on the fly.
If you like popups for displaying documentation, convert the uncompressed man pages (groff -t -e -mandoc -Tascii <man-page> | col -bx), and set keywordprg to your own wrapper to search for keywords according to your needs.

vi/vim - custom formatting depending on presence of special file or tag inside code

Question
Is there a simple/reliable way to have VIM, on a project/directory specific base, either detect a special file (ie: custom .vimrc with a couple settings), or to change run-time settings based on the presence of a special tag/string/hash in a comment at the beginning of a c source (.c) or header (.h) file? The string/hash must map to a function/setting in the .vimrc file, and must not contain the actual settings themselves.
Background
I have a mutli-developer project where we all have a common set of code style settings for our various editors (emacs and vim, primarily), and we all adhere strictly to these settings, such as newline style (CR versus CR+LF), indentation (length, hard-tabs versus expanded-as-spaces), and so on.
Problem
I'm creating a few new projects that, for reasons beyond our control (ie: static code analysis tool we have to use), will require different style settings than ours. There are ways to bypass this in the static code analysis tool, but there's a non-technical/legal requirement that we avoid disabling "features" of this tool.
For each of these new projects, I would like to somehow make vi/vim aware of some special flag, either by the presence of a special file in the root of the project's directory structure, or by a special keyword/tag/hash/etc I could put inside a /* C-style block comment */. When vi/vim is aware of the presence of this "trigger", I would want it to invoke a function to override the style settings for newlines, indentation, etc. If this is possible, is it also possible to have several, mutually exclusive such "triggers" so that everyone has a common .vimrc and the project determines which style to utilize?
Question - redux
Is there a straightforward way to accomplish this?
One solution: modelines (:help modeline) for Vim and file variables for Emacs.
Those are special comments you put in your files that are interpreted by your editor. You can use them to set indent style, file encoding, etc.
In my opinion, modelines are ugly noise.
One solution for Vim: .exrc (:help 'exrc').
You can put your project-specific settings in a .exrc file at the root of your project. The manual claims this solution is insecure but I fail to see how normal functioning adult could be beaten by it. YMMV.
One solution for Vim: directory-specific autocommands.
That's the safer alternative mentioned at the end of :help 'exrc' but it requires each contributor to add stuff to his own vimrc so… not that useful I guess.
The definitive solution: editorconfig.
You put your settings in a .editorconfig at the root of your project and let each contributor's IDE/editor deal with it.
... to change run-time settings based on the presence of a special
tag/string/hash in a comment at the beginning of a c source (.c) or
header (.h) file?
Yes, they're called modelines. http://vim.wikia.com/wiki/Modeline_magic
They can appear at the start or end of files.
An example from some C sources of mine:
/* vim:ft=c:expandtab:sw=4:ts=4:sts=4:
*/
See :help modeline in vim for more info.
Central configuration
If it's okay to configure the specific commands / local exceptions centrally, you can put such autocmds into your ~/.vimrc:
:autocmd BufRead,BufNewFile /path/to/dir/* setlocal ts=4 sw=4
It is important to use :setlocal instead of :set, and likewise :map <buffer> ... and :command! -buffer ....
On the other hand, if you want the specific configuration stored with the project (and don't want to embed this in all files via modelines), you have the following two options:
Local config with built-in functionality
If you always start Vim from the project root directory, the built-in
:set exrc
enables the reading of a .vimrc file from the current directory. You can place the :set ts=4 sw=4 commands in there.
Local config through plugin
Otherwise, you need the help of a plugin; there are several on vim.org; I can recommend the localrc plugin (especially with my own enhancements), which even allows local filetype-specific configuration.
Note that reading configuration from the file system has security implications; you may want to :set secure.
I've covered the main alternatives in this answer : https://stackoverflow.com/a/456889/15934 (Yes, your question is almost a duplicate: different formulation, but same solutions).
Modelines are really limited: you have to use a plugin to set things that are not vim options.
.exrc doesn't look behind the current directory
editorconfig is restricted to very specific options: don't expect to forward plugin specifications like where compilation directories are (this is how I support multiple compilation modes with CMake -- others prefer playing with ccache and tuning the CMakeCache, but this doesn't work well when using g++ and clang++ one after the other), how the linter shall be called, your naming conventions...
autocommand don't scale and cannot be ported easily from one directory to the other.
In the end, the best solutions are plugin based IMO: There a plenty plugin solutions see the non exhaustive list at the end of my local_vimrc plugin's README
Note also that since my previous answer, I've initiated another experiment to simplify project management. For instance, I introduce p:variables which are variables shared among all buffers belonging to a project.

make file running on Linux - how to ignore case sensitive?

I have a huge project, whole written in C language and I have a single make file that is used to compile it. The project C files contains lots of capitalize problems in it's header files, meaning there are tones of header files that were miss-spelled in lots of C files.
The problem is I need to migrate this project to compile on Linux machine and since Linux is case sensitive I got tones of errors.
Is there an elegant way which I can run make file in Linux and tell him to ignore case sensitive?
Any other solution will be welcome as well.
Thanks a lot.
Motti.
You'll have to fix everything by hand and rename every file or fix every place with #include. Even if you have a huge project (comparable with linux kernel), it should be possible to do this during a hour or two. Automation may be possible, but manual way should be better - because script won't be able to guess which name is right - filename, or the name used in #include.
Besides, this situation is a fault of original project developer. If he/she wasn't sloppy and named every header in every #include correctly, this wouldn't happen. Technically, this is a code problem similar to syntax error. The only right way to deal with it is to fix it.
I think it takes not too long to write a small script, which goes thru the directories first, then replaces C headers. Explained:
Scan the headers' folder and collect filenames.
Make a lowercase list of them. You have now original and locased pairs.
Scan the C source files and find each line contains "#include"
Lowercase it.
Find the lowercase filename in the list collected and lowercased from headers.
Replace the source line with the one collected from headers.
You should put the modified files into a separate folder structure, avoid overwriting the whole source with some buggy stuff. Don't forget to create target folders during the source tree scan.
I recommend a script language for that task, I prefer PHP, but just it's the only server-side script language which I know. Yep, it will run for a while, but only once.
(I bet that you will have other difficulties with that project, this problem is not a typical indicator of high quality work.)
Well I can only tell you that you need to change the case of those header files. I don't know that there is any way you can make it automatic but still you can use cscope to do it in a easier way.
http://www.linux-tutorial.info/modules.php?name=ManPage&sec=1&manpage=cscope
You can mount the files on a case-insensitive file system. FAT comes to mind. ntfs-3g does not appear to support this.
I use the find all and replace all functionality of Source Insight when i have to do complete replacement. But your problem seems quite big, but you can try the option to replace every header file name in all occurences of source files using the
"Find All" + "Replace" functionality. You can use notepad++ too for doing the same.
A long time ago there was a great tool under MPW (Macintosh Programmer's Workshop) called Canon. It was used to canonize text files, i.e. make all symbols found in a given refernce list have have the same usage of upper/lower case. This tool would be ideal for a task like this - I wonder if anything similar exists under Linux ?

Graph of included files

When I work on someone else's code, I tipically need to abuse of grep in order to find data types declarations etc, and this usually makes me confused.
I'd like to have some tool which analyzes the source code and produces some graphviz-like drawing and allows me to follow dependencies.
Also I've found this on the internet, but I think is taylored for the linux kernel only.
Have you tried doxygen?
Doxygen can produce dot files, and you can build the documentation without changing the source code with the right options set in the Doxyfile.
Do you use an editor that can take advantage of tags ? In Emacs, I just type M-. to go to the definition of a symbol, and M-* to go back to where I was once I have read it. This also enables the command tags-search to grep among the files of the software project (very convenient if they are in multiple directories).

Distributing loadable builtin bash modules

I've written a built-in for bash which modifies the 'cd' command, a requirement for my software. Is there a way to actually distribute a loadable independently of bash itself? I'd ideally like to distribute just a drop in "additional feature" because I know people can be put off by patching and compiling their shell from source code.
I want to time how long a user is in a directory so I can determine where they want to be. It's this functionality: http://github.com/joelthelion/autojump/tree/master rewritten as a bash builtin, for performance issues. This implementation uses $PROMPT_COMMAND to work but I wanted something integrated.
It is unclear what you have modified but in any case, bash (like at least ksh93 which IIRC introduced the concept and zsh) supports, using the enable -f file name syntax, loading built-in functions as external dynamically loaded modules.
These modules being plain files can certainly be distributed independently, as long as you make sure they are compatible with the target version/architecture. This was already true 5 years ago when you asked this question.
One issue in your case is there seems to be no documented way to overload a internal built-in like cd by a dynamically loaded one while keeping the ability to access the former.
A simple workaround would be to implement your customized cd with a different name, say mycd, like this:
int mycd_builtin(list)
WORD_LIST *list;
{
int rv;
rv=cd_builtin(list);
if(rv == EXECUTION_SUCCESS) {
char wd[PATH_MAX+1];
getcwd(wd,sizeof(wd));
// do your custom stuff knowing the new working directory
...
}
return (rv);
}
then to use an alias, or better, a shell function for your customized version to be used instead of the regular one:
cd() {
mycd "$#"
}
As long as your customization doesn't affect the behavior of the standard command and thus doesn't risk breaking scripts using it, there is nothing wrong in your approach.
Changing the built-in cd is a support nightmare for any admin and unwelcome to foreign users. What is wrong with naming it 'smart-cd' and letting the USER decide if they want the functionality by including it in their .bashrc or .profile? Then they can setup things however they want.
Also, using how long you've been in a directory is a pretty poor indication of preference. How would you distinguish between idling (a forgotten shell hanging in /tmp overnight), long-running scripts (nightly cron jobs), and actual activity.
There are a multitude of other methods for creating shortcuts to favorite directories: aliases, softlinks, $VARIABLES, scripts. It is arrogant of you to assume that your usage patterns will be welcomed by other users of your system.

Resources