Automatic indexing of project files
Despite the fact that there are a lot of articles on the topic “using Vim as an IDE”, the result did not satisfy me. I really lacked the automatic, transparent for the user (that is, me) tag generation for all files in the project, and the project files do not have to be in the same directory and its subdirectories, and creating a list of files should be easy and pleasant.
In addition, I should be able to easily transfer the project from one computer to another and should not be tied to a specific project directory.
Long searches for plugins with the necessary functionality were unsuccessful, so it was decided to write such a plugin. I called it indexer .
UPD:At the moment, the article is slightly outdated. I will update it when I have time for this. However, the main thing works, and backward compatibility is provided, but for a more complete use of the features, I recommend you read : help indexer-syn-change-4.10 .
The archive with the plugin contains the following files and folders: ctags are required for operation , but ctags are better patched, because in the latest version 5.8 (at the time of writing these lines) there is a very unpleasant bug. Read more about the bug and download the patch here . First of all, it should be said that there are two options for using the plugin: as an addition to the wonderful project plugin or separately from it.
A few words about the project plugin: this plugin allows you to conveniently manage projects and a list of files in them. Visually, this is a window with a tree structure of projects, subprojects and files. Projects can be minimized. You can do grep or vimgrep on all project files, and then view the results in quickfix. It is convenient to map some key (for example, F9) to show / hide the window with projects.
A detailed description of this plugin is beyond the scope of this article, in addition, the query “vim project” in Google immediately gives a lot of links. Offhand - here . Well and, of course,: help project after installing the plugin.
So, consider the simplest option: you already use the project plugin and use the default project file ~ / .vimprojects. If so, then setting up the indexer plugin will be very simple: you simply unpack the contents of the archive in $ HOME / .vim (or a similar directory), close Vim (if it was open) and run it from any directory of any project in ~ / .vimprojects . You can simply open any file that is part of the project.
Indexer will determine that a file that is part of such and such a project has been opened, index all the files that are part of this project and set the corresponding values to the Vim & tags and & path variables.
Tags will be automatically updated when you save any file that is part of the project.
Now you can move the cursor to the name of a function, variable, etc., and by pressing g] or Ctrl-] (there are slight differences), move to the declaration of this function. Ctrl-t will bring you back. And if you are developing in C / C ++, you can connect the omnicppcomplete and code_complete plugins, and then by typing "structure_name." Or "structure_name->", you will see a popup menu with a choice of elements of this structure, and typing "function_name (" and by pressing Tab, you get the auto-substitution of all parameters that this function accepts. But I got a little distracted.
It all looks something like this: If you use the project plugin, but you have a different project file, you can specify it in your _vimrc:
I will give a complete list of options a bit later.
As you can see, working with a bunch of these plugins is quite convenient: project allows you to manage projects, and indexer takes care of updating tags.
If for some reason you do not want to use project, then
You will need to describe in one file which files are part of which projects. The default is ~ / .indexer_files. The syntax for this file is quite simple. Perhaps the best way to explain is to give an example: as you might guess, there are two projects: CoolProject and AnotherProject. The CoolProject project includes all * .c files from the / home / user / myproject / src directory, and all header files from / home / user / myproject / inc and / home / user / myproject / src. And AnotherProject includes * .c and * .h files from the ~ / myproject2 directory and all subdirectories recursively ("**" indicates recursion). Well, as you can see, in the file paths you can use Vim variables, such as $ HOME, $ VIM, and others, including those declared by the user. UPD
: In version 1.5, at the request of the torkve user , the ability to set a directory containing many projects in this file is added. Suppose you have a ~ / workspace directory that contains a bunch of projects, and the list of projects often changes. Each time, editing the .indexer_files file will be lazy. Then you can specify something like this: The keyword is PROJECTS_PARENT. Indexer will consider each folder in ~ / workspace as a separate project, which includes files of the listed types. In all other respects, indexer works in exactly the same way as with project: if you run Vim from the project directory, then tags for all files from this project will be generated, and if any file from this project is saved, the tags will be updated.
That's it, now I can just create projects, add files there and forget about how they are indexed. Hurrah!
But this was not enough for me.
The thing is, I don’t like it when project files are in different places (with the exception of libraries that will be shared by several projects. In fact, libraries are separate projects). In the cases considered by us, the project lies in one folder, and the file with the project description (.vimprojects or .indexer_files) is in another (in the home).
That is, I would like for each project to have its own .vimprojects file, which would lie in the folder of the project itself and in which, in fact, there would be a description of only this project. It turns out, depending on the project, you need to load the settings specific to this project.
I solved this problem as follows: in the root folder of the project I create a folder ".vimprj" (the name can be changed), in which I put the files with the project-specific settings. In it lies .vimprojects. When Vim starts, indexer will first look for this ".vimprj" folder in the current directory, if it is not there, go to the next level, and so on. The recursion depth can be changed, by default it is 10.
If the ".vimprj" folder is found, then indexer will declare a global variable $ INDEXER_PROJECT_ROOT, in which, as you might guess, the path to the project root folder will be indicated. Not to the ".vimprj" folder, but to the folder in which ".vimprj" lies. All * .vim files from this directory will also be launched, in which you can set specific settings. Here is an example of such a sett.vim file:
Also in the project file .vimprojects I do not use the absolute path to the project, but substitute the variable $ INDEXER_PROJECT_ROOT. Now I can move the project folder wherever I want, in any case, all the paths will be correct and the tags will be generated. This is what I wanted to achieve.
Now a few details.
The only possibility provided by Aric Blumer, the creator of the plugin, is to give the command ": Project /path/to/my/.vimprojects" every time Vim starts. Of course, you can map it to some key, but it’s still a “crutch”, and it’s inconvenient: you can just forget to press this key. You can run vim with the optional key + "Project /path/to/my/.vimprojects", but I don't like that either. I corresponded with the creator of the plugin, but he told me that I was the only one who needed it, and he would not change anything. So I can only tell you how to change project.vim so that you can specify a variable with the project file. Instead of one line, you will need to insert 5 lines, that's all.
The above is true for project 1.4.1 (the latest version at the time of this writing).
Go to line 1272. There should be only one command in it: You
need to replace this line with the following code block: Everything, now if you specify the variable g: proj_project_filename, then its value will be used instead of ~ / .vimprojects UPD : In Indexer version 3.0 appeared two "features" very important for me: 1.
Tags are generated in the background. This means that regardless of the size of your project, you will not have to wait until the entire project is indexed. There is one BUT: this only works if servername is not empty (: help servername). When you run gvim (and not vim), it itself sets the default servername "GVIM", that is, in gvim the background tag generation will work out of the box. And if you use the console vim and want the tags to be generated in the background, then you need to run it with something like this:
2.You can open files from different projects in one vim session, and tags will be generated correctly for all the necessary projects. Tags from different projects do not mix. This is damn convenient when you need to work with several projects at the same time. (for example, projects of several entities interacting with each other)
g: indexer_lookForProjectDir (default: 1)
If 1, then the plugin will search for the ".vimprj" folder.
g: indexer_dirNameForSearch (default: ".vimprj")
Name of the project settings directory
g: indexer_recurseUpCount (default: 10)
The recursion depth to search for this folder
g: indexer_projectsSettingsFilename (default: "~ / .vimprojects")
Path and file name projects (project plugin file)
g: indexer_indexerListFilename (default: "~ / .indexer_files")
The path and name of the project file (native indexer plugin format).
If both files exist (both ".indexer_files" and ".vimprojects"), then only .indexer_files is used. Another file will be ignored. To find out which file is currently being used, you can use the command: IndexerInfo. I’ll tell you more about indexer plugin commands below.
g: indexer_projectName (default: "")
The name of the project to read from the project file. If the project name is not specified, then any project will be used.
g: indexer_enableWhenProjectDirFound (default: 1)
If 1, then indexer will index the project files if Vim was launched from any directory in which the project files are located.
If 0, then the files will be indexed only if the file was opened,
g: indexer_tagsDirname (default: "")
Directory for saving tags.
If this option is empty (by default), then the name of the folder with tags is selected as follows:
Suppose you use the file ~ / .indexer_files. Then the tags will be saved in the ~ / .indexer_files_tags / project_name folder, where project_name is the name of the project.
If you use the ~ / .vimprojects file. Then the tags will be saved in the ~ / .vimprojects_tags / project_name folder, where project_name is the name of the project.
If this option is not empty, then all tag files are saved in the specified folder.
I recommend leaving this option blank.
g: indexer_ctagsCommandLineOptions (default: "--c ++ - kinds = + p + l --fields = + iaS --extra = + q")
Options with which ctags will be launched.
g: indexer_ctagsJustAppendTagsAtFileSave (default: for Linux: 1, for Windows: 0)
If 1, then when saving any file from the project, ctags will be launched with the "-a" (append) switch for this file only.
(Here you also need to pay attention to the g: indexer_useSedWhenAppend option : when it is installed, then before updating the tags, the old tags from this file will be deleted using the Sed utility)
If 0, then when saving any file from the project, the tags will be completely updated.
There are some difficulties. All versions of Sed for Windows that I managed to find work crookedly. I will not talk about their glitches here, I will only say that I did not succeed in getting them to work correctly. And on Linux it works well. Therefore, I had to compromise: in Linux, by default, tags are updated only for the saved file, and Sed is used to remove “garbage” from the tag file; and on Windows, every save just updates all the tags. In fact, with the advent of background tag generation in Indexer 3.0, this is no longer a problem.
: IndexerInfo
Displays information about the current state of the plugin: which project file is used, how many files are indexed, how many and which files were not found, etc.
If for some reason the plugin does not work as you expect, then the first thing to do is give this command.
: IndexerRebuild
Updates tags for all files included in the project.
Indexer plugin page: http://www.vim.org/scripts/script.php?script_id=3221
project plugin page: http://www.vim.org/scripts/script.php?script_id=69
Patched ctags: http : //dfrank.ru/ctags581
Thank you for your attention.
In addition, I should be able to easily transfer the project from one computer to another and should not be tied to a specific project directory.
Long searches for plugins with the necessary functionality were unsuccessful, so it was decided to write such a plugin. I called it indexer .
UPD:At the moment, the article is slightly outdated. I will update it when I have time for this. However, the main thing works, and backward compatibility is provided, but for a more complete use of the features, I recommend you read : help indexer-syn-change-4.10 .
The archive with the plugin contains the following files and folders: ctags are required for operation , but ctags are better patched, because in the latest version 5.8 (at the time of writing these lines) there is a very unpleasant bug. Read more about the bug and download the patch here . First of all, it should be said that there are two options for using the plugin: as an addition to the wonderful project plugin or separately from it.
plugin/indexer.vim
doc/indexer.txt
A few words about the project plugin: this plugin allows you to conveniently manage projects and a list of files in them. Visually, this is a window with a tree structure of projects, subprojects and files. Projects can be minimized. You can do grep or vimgrep on all project files, and then view the results in quickfix. It is convenient to map some key (for example, F9) to show / hide the window with projects.
A detailed description of this plugin is beyond the scope of this article, in addition, the query “vim project” in Google immediately gives a lot of links. Offhand - here . Well and, of course,: help project after installing the plugin.
Option 1. Use as an addition to the project plugin
So, consider the simplest option: you already use the project plugin and use the default project file ~ / .vimprojects. If so, then setting up the indexer plugin will be very simple: you simply unpack the contents of the archive in $ HOME / .vim (or a similar directory), close Vim (if it was open) and run it from any directory of any project in ~ / .vimprojects . You can simply open any file that is part of the project.
Indexer will determine that a file that is part of such and such a project has been opened, index all the files that are part of this project and set the corresponding values to the Vim & tags and & path variables.
Tags will be automatically updated when you save any file that is part of the project.
Now you can move the cursor to the name of a function, variable, etc., and by pressing g] or Ctrl-] (there are slight differences), move to the declaration of this function. Ctrl-t will bring you back. And if you are developing in C / C ++, you can connect the omnicppcomplete and code_complete plugins, and then by typing "structure_name." Or "structure_name->", you will see a popup menu with a choice of elements of this structure, and typing "function_name (" and by pressing Tab, you get the auto-substitution of all parameters that this function accepts. But I got a little distracted.
It all looks something like this: If you use the project plugin, but you have a different project file, you can specify it in your _vimrc:
let g:indexer_projectsSettingsFilename = /path/to/my/.vimprojects
I will give a complete list of options a bit later.
As you can see, working with a bunch of these plugins is quite convenient: project allows you to manage projects, and indexer takes care of updating tags.
If for some reason you do not want to use project, then
Option 2. Use without project plugin
You will need to describe in one file which files are part of which projects. The default is ~ / .indexer_files. The syntax for this file is quite simple. Perhaps the best way to explain is to give an example: as you might guess, there are two projects: CoolProject and AnotherProject. The CoolProject project includes all * .c files from the / home / user / myproject / src directory, and all header files from / home / user / myproject / inc and / home / user / myproject / src. And AnotherProject includes * .c and * .h files from the ~ / myproject2 directory and all subdirectories recursively ("**" indicates recursion). Well, as you can see, in the file paths you can use Vim variables, such as $ HOME, $ VIM, and others, including those declared by the user. UPD
[CoolProject]
/home/user/myproject/src/*.c
/home/user/myproject/src/*.h
/home/user/myproject/inc/*.h
[AnotherProject]
$HOME/myproject2**/*.c
$HOME/myproject2**/*.h
: In version 1.5, at the request of the torkve user , the ability to set a directory containing many projects in this file is added. Suppose you have a ~ / workspace directory that contains a bunch of projects, and the list of projects often changes. Each time, editing the .indexer_files file will be lazy. Then you can specify something like this: The keyword is PROJECTS_PARENT. Indexer will consider each folder in ~ / workspace as a separate project, which includes files of the listed types. In all other respects, indexer works in exactly the same way as with project: if you run Vim from the project directory, then tags for all files from this project will be generated, and if any file from this project is saved, the tags will be updated.
[PROJECTS_PARENT filter="*.c *.h *.cpp"]
~/workspace
That's it, now I can just create projects, add files there and forget about how they are indexed. Hurrah!
But this was not enough for me.
The thing is, I don’t like it when project files are in different places (with the exception of libraries that will be shared by several projects. In fact, libraries are separate projects). In the cases considered by us, the project lies in one folder, and the file with the project description (.vimprojects or .indexer_files) is in another (in the home).
That is, I would like for each project to have its own .vimprojects file, which would lie in the folder of the project itself and in which, in fact, there would be a description of only this project. It turns out, depending on the project, you need to load the settings specific to this project.
I solved this problem as follows: in the root folder of the project I create a folder ".vimprj" (the name can be changed), in which I put the files with the project-specific settings. In it lies .vimprojects. When Vim starts, indexer will first look for this ".vimprj" folder in the current directory, if it is not there, go to the next level, and so on. The recursion depth can be changed, by default it is 10.
If the ".vimprj" folder is found, then indexer will declare a global variable $ INDEXER_PROJECT_ROOT, in which, as you might guess, the path to the project root folder will be indicated. Not to the ".vimprj" folder, but to the folder in which ".vimprj" lies. All * .vim files from this directory will also be launched, in which you can set specific settings. Here is an example of such a sett.vim file:
" определяем путь к папке .vimprj
let s:sPath = expand(':p:h')
" указываем плагину indexer файл проекта, который лежит в папке .vimprj
let g:indexer_projectsSettingsFilename = s:sPath.'/.vimprojects'
" указываем плагину project файл проекта, который лежит в папке .vimprj
" ВНИМАНИЕ: этой переменной нет в стандартном project.
" Вам нужно немного изменить файл project.vim, чтобы это сработало
" об этом чуть ниже
let g:proj_project_filename=s:sPath.'/.vimprojects'
" можно еще, например, указать специфический для этого проекта компилятор
let &makeprg = 'pic30-gcc -mcpu=24HJ128GP504 -x c -c "%:p" -o"%:t:r.o" -I"'.$INDEXER_PROJECT_ROOT.'\src\utils" -I"'.$INDEXER_PROJECT_ROOT.'\src\app" -g -Wall -mlarge-code -mlarge-data -O1'
Also in the project file .vimprojects I do not use the absolute path to the project, but substitute the variable $ INDEXER_PROJECT_ROOT. Now I can move the project folder wherever I want, in any case, all the paths will be correct and the tags will be generated. This is what I wanted to achieve.
Now a few details.
About how to specify the project file to the project plugin different from ~ / .vimprojects.
The only possibility provided by Aric Blumer, the creator of the plugin, is to give the command ": Project /path/to/my/.vimprojects" every time Vim starts. Of course, you can map it to some key, but it’s still a “crutch”, and it’s inconvenient: you can just forget to press this key. You can run vim with the optional key + "Project /path/to/my/.vimprojects", but I don't like that either. I corresponded with the creator of the plugin, but he told me that I was the only one who needed it, and he would not change anything. So I can only tell you how to change project.vim so that you can specify a variable with the project file. Instead of one line, you will need to insert 5 lines, that's all.
The above is true for project 1.4.1 (the latest version at the time of this writing).
Go to line 1272. There should be only one command in it: You
Project
need to replace this line with the following code block: Everything, now if you specify the variable g: proj_project_filename, then its value will be used instead of ~ / .vimprojects UPD : In Indexer version 3.0 appeared two "features" very important for me: 1.
if !exists("g:proj_running") && exists('g:proj_project_filename')
exec('Project '.g:proj_project_filename)
else
Project
endif
Tags are generated in the background. This means that regardless of the size of your project, you will not have to wait until the entire project is indexed. There is one BUT: this only works if servername is not empty (: help servername). When you run gvim (and not vim), it itself sets the default servername "GVIM", that is, in gvim the background tag generation will work out of the box. And if you use the console vim and want the tags to be generated in the background, then you need to run it with something like this:
$ vim --servername MY_SERVER
2.You can open files from different projects in one vim session, and tags will be generated correctly for all the necessary projects. Tags from different projects do not mix. This is damn convenient when you need to work with several projects at the same time. (for example, projects of several entities interacting with each other)
Indexer plugin options
g: indexer_lookForProjectDir (default: 1)
If 1, then the plugin will search for the ".vimprj" folder.
g: indexer_dirNameForSearch (default: ".vimprj")
Name of the project settings directory
g: indexer_recurseUpCount (default: 10)
The recursion depth to search for this folder
g: indexer_projectsSettingsFilename (default: "~ / .vimprojects")
Path and file name projects (project plugin file)
g: indexer_indexerListFilename (default: "~ / .indexer_files")
The path and name of the project file (native indexer plugin format).
If both files exist (both ".indexer_files" and ".vimprojects"), then only .indexer_files is used. Another file will be ignored. To find out which file is currently being used, you can use the command: IndexerInfo. I’ll tell you more about indexer plugin commands below.
g: indexer_projectName (default: "")
The name of the project to read from the project file. If the project name is not specified, then any project will be used.
g: indexer_enableWhenProjectDirFound (default: 1)
If 1, then indexer will index the project files if Vim was launched from any directory in which the project files are located.
If 0, then the files will be indexed only if the file was opened,
g: indexer_tagsDirname (default: "")
Directory for saving tags.
If this option is empty (by default), then the name of the folder with tags is selected as follows:
Suppose you use the file ~ / .indexer_files. Then the tags will be saved in the ~ / .indexer_files_tags / project_name folder, where project_name is the name of the project.
If you use the ~ / .vimprojects file. Then the tags will be saved in the ~ / .vimprojects_tags / project_name folder, where project_name is the name of the project.
If this option is not empty, then all tag files are saved in the specified folder.
I recommend leaving this option blank.
g: indexer_ctagsCommandLineOptions (default: "--c ++ - kinds = + p + l --fields = + iaS --extra = + q")
Options with which ctags will be launched.
g: indexer_ctagsJustAppendTagsAtFileSave (default: for Linux: 1, for Windows: 0)
If 1, then when saving any file from the project, ctags will be launched with the "-a" (append) switch for this file only.
(Here you also need to pay attention to the g: indexer_useSedWhenAppend option : when it is installed, then before updating the tags, the old tags from this file will be deleted using the Sed utility)
If 0, then when saving any file from the project, the tags will be completely updated.
There are some difficulties. All versions of Sed for Windows that I managed to find work crookedly. I will not talk about their glitches here, I will only say that I did not succeed in getting them to work correctly. And on Linux it works well. Therefore, I had to compromise: in Linux, by default, tags are updated only for the saved file, and Sed is used to remove “garbage” from the tag file; and on Windows, every save just updates all the tags. In fact, with the advent of background tag generation in Indexer 3.0, this is no longer a problem.
Indexer Plugin Commands
: IndexerInfo
Displays information about the current state of the plugin: which project file is used, how many files are indexed, how many and which files were not found, etc.
If for some reason the plugin does not work as you expect, then the first thing to do is give this command.
: IndexerRebuild
Updates tags for all files included in the project.
And finally, links
Indexer plugin page: http://www.vim.org/scripts/script.php?script_id=3221
project plugin page: http://www.vim.org/scripts/script.php?script_id=69
Patched ctags: http : //dfrank.ru/ctags581
Thank you for your attention.