visualize dependence on global variables using vim, ctags potentially - vim

I'd like to highlight variables in my (Maple-code, but doesn't matter much) code which are global for routines.
e.g. I have
global_var1:=1;
global_var2:=2;
...
some_proc:=proc()
local local_var1, global_var2;
local_var1:=1;
local_var2:=local_var1*global_var1+global_var2;
end proc;
I want to highlight global_var1 inside of some_proc() in this example. Obviously the naming is not so trivial in general as in the example.
Can I use ctags to do this?

It depends on ctags. With some languages it is unable to extract local variables (viml), with other languages, it doesn't detect all local variables (C++). Hence, the first thing you'll have to do is to see what ctags can do for your language (Maple).
The other difficulty is to restrict the highlighting to one specific function, and to stay synchronized every time newlines are inserted to the edited file. I know no easy way to do this -- may be with a vim syntax region that starts at local.*{global-name} and ends at end proc to neutralize the highlighting of all global variables?
One task that'll be much more easier would be to highlight variable masking, i.e. highlight global_var2 at the point in the function where it is declared local. Alas, it's not what you're looking for.

Related

Context sensitive word wrap in vi/vim

How can I can specific word wrapping for specific tags. For example, in LaTex I want word wrapping for my paragraphs but not for my figure commands (they are always very long and run off the screen).
Or with Javascript, I want the right margin for code to be at, for example 50 columns, but for the comments to be at only 40 columns
This is not builtin
You could probably script something yourself using a devious combination of `formatexpr` and synID(). I suggest you look at the help of the latter first, because it contains inspirational samples:
for id in synstack(line("."), col("."))
echo synIDattr(id, "name")
endfor
taken from :he synstack
The formatexpr is usually set to something like
:set formatexpr=mylang#Format()
thus delegating to a filetype plugin. You could implement the function to use different margins for different syntax contexts.
Bear in mind
the default formatexpr (if absent, formatprg) are probably no good for a source file (in my experience it has the tendency to string together lines as if they were text paragraphs). But then again, you can implement it any which way you want
that syntax highlighting may become out of sync. I'm not sure what happens when the cursor is at, say, 70% of a large document and you issue ggVGgq. It might not update the syntax highlighting all the way (meaning that your formatexpr function would get the 'wrong' synID() values. You get around this by saying something like
:syntax sync fromstart
this again might impact the highlighting performance depending on the size/complexity of the source and highlighting scripts

Lookup a specific kind of tag in Vim

So here's my problem. I've gotten exuberant ctags working with Vim, and it works great, most of the time. One thing that still irks me though is whenever I try to search for a function that is named the same as some variable name. I sometimes get the right tag on the first try, sometimes not. Then after I pull up the list of alternate tags with :tselect, it comes up with a list of tags for both function definitions or variable definitions/assignments. (I'm in PHP so definitions and assignments are syntactically indistinguishable).
However, I notice that there's a column labeled 'kind' that has a value of 'f' or 'v', for function and variable, respectively. I can't seem to find a whole lot of information about this field, it seems like it may not be exactly standardized or widely used. My question is: can you filter tag results in Vim by "kind"?
Ideally, the default would be to search the whole tags file, but by specifying some extra flag, you could search a specific ('f' or 'v') kind only.
This is such a small problem for me as it doesn't come up THAT often, but sometimes it's the small problems that really annoy you.
You can certainly generate ctag files with any combination of php-kinds that you want (see the ouput of the command ctags --list-kinds.)
If you feel it's worth the effort you can make a vim function tagkind and bind it to a command. The tagkind function can overwrite the current tags vim variable to point at only the tag file with the kinds that you are interested in and call :tag. Optionally, it can store the previous version of the tags variable and restore it after this one call.
Unfortunately, I don't know of anyway other than this. Perhaps someone else would know.
I generate python ctags with --python-kinds=-i to exclude tags for import statements (which are useless). Maybe you could generate with --php-kinds=-v and drop a class of tags completely.
You can read :help tag-priority. Apparently the "highest-priority" tag is chosen based on some hard-coded logic.
fzf with fzf.vim has a :Tags (for the whole project) and :BTags for the current file option that generates ctags on the fly.
An issue raised on the plugin 'Skip tag kinds in :BTags and :Tags' gives the following code that you can use to only generated tags for a particular kind. I've modified the below so that it should only search for the PHP f kind.
command! BTagsEnhanced
\ call fzf#vim#buffer_tags(<q-args>, [
\ printf('ctags -f - --sort=no --php-kinds=f --excmd=number --language-force=%s %s', &filetype, expand('%:S'))], {})
Note as per my comment on the question, there is a potential Vim tagfinder.vim plugin via a blog post on Vim and Ctags: Finding Tag Definitions. But I haven't tried it.

Adding a syntax group to ALL syntaxes

I want to add a syntax group to all syntaxes. Namely, I want to highlight characters like +,-,*,/ and other punctuation chars for every programming language. I know that I can add a <language>.vim file for every language to my .vim/after/syntax folder, but I want to make this generic. Currently I have to create one such (exactly the same) syntax addendum file for every programming language, and that's... inelegant.
Basically I'd like to place an all.vim file in .vim/after/syntax and have the contents of that file added to every syntax file. I'm fairly sure that this option doesn't exist (I checked the vim docs), so I'm looking for some way to emulate that. Is there perhaps a programmatic way of adding the new syntax group to every syntax?
You could simply place it in your vimrc.

vim functions with script scope

I had installed Janus with my MacVim setup. In order to learn about how vim scripts work, I've been reading through the vimrc file that Janus uses, and I don't understand how the author of this is using functions. For example, here's one of the functions in the vimrc:
function s:setupWrapping()
set wrap
set wrapmargin=2
set textwidth=72
endfunction
Now, according to the Defining a function section of the vim manual, 'Function names must begin with a capital letter.' According to the Local mappings and functions section of the manual, 'When defining a function in a script, "s:" can be prepended to the name to make it local to the script.' However, there's no mention of being able to begin a function name with a lower case letter when specifying its scope as local to the script.
So, is the function as written syntactically incorrect but works anyway, or is it syntactically correct but I can't find the documentation that says so?
As I understand it, the rule about capitalizing function names is intended to avoid conflicts with vim's built-in functions. There's no possibility of conflict from script-local functions, so it seems reasonable that the restriction would not apply to them, since you must always prefix them with their namespace qualifier.
ZyX corrected me in the comments, pointing out that, contradictory to an earlier revision of this answer, vim does not allow buffer-scope functions to be declared. You can declare a global function with a name like b:function_name, or for that matter _:function_name, but this is confusing and probably a terrible idea, for reasons mentioned in the comments.
Functions declared within a dictionary do not need to be capitalized.
Buffer-scope Funcrefs, and presumably other Funcrefs outside of global or function-level scope ("local" Funcrefs) do not need to be capitalized. But they have limited usefulness anyway, since a Funcref must reference either a global or script-scope function (the latter being syntactically awkward) or a dictionary function; in the latter case you have to call it with call(funcref, args, dict).
But anyway, you're looking for documentation, so I did a :helpgrep capital and found these nuggets of wisdom:
E704: A Funcref variable must start with a capital, "s:", "w:", "t:" or "b:".
E124: « Define a new function by the name {name}. The name must be made of alphanumeric characters and '_', and must start with a capital or "s:" (see above). » The "see above" pointer refers to the sections user-functions and local-function, which provide more detail but don't mention anything about the non-capitalization of script-scope functions. user-functions mentions that The function name must start with an uppercase letter, to avoid confusion with builtin functions.
It may be that the strict rule of always starting a function name with a capital was true before the advent of other scopes, of which script scope seems to have been the first, or at least the first capable of including function declarations. I'm guessing that the parts of the manual which assert such a rule have just not been updated to reflect the state of modern vim.
I suppose you'll never know if there's documentation but you can't find it.
However, I looked at Derek Wyatt's vimrc file on his blog and he consistently uses a capital first letter in function names.
This just proves, only, that he's read the manual too.

Is it possible to format C++ code with VIM?

I am rather new to VIM. I got some source code and this is a mess. At a first sight I would like at least to get a clear and organised view of the code, so I like to get it rightly formatted, I mean indented depending on the depth of the functions and so.
I wonder if it can be done with VIM, and otherwise which other commandline tools for that can you recommend.
Thanks
While vim is a true Swiss-knife I still prefer external tools for some jobs. This approach is some times much more intuitive and easy to remember than using the built-in equivalent.
In the case of indenting, I filter the whole file buffer through astyle. The astyle parameters are much easier to grasp in a couple of minutes, especially if you are not a vim guru. Also astyle provides much more flexibility in fine-tuning the output.
First install astyle:# apt-get install astyle
Then inside vim:
:%!astyle (simple case - astyle default mode is C/C++)
or
:%!astyle --mode=c --style=ansi -s2 (ansi C++ style, use two spaces per indent level)
or
:1,40!astyle --mode=c --style=ansi (ansi C++ style, filter only lines 1-40)
you can do the following:
gg=G
I would highly recommend clang-format nowadays. It allows simple integration of clang-format into Vim, once you have clang-format installed:
http://clang.llvm.org/docs/ClangFormat.html#vim-integration
It is the only code beautifier that really understands your C++ code, and it is really intelligent to beautify the code more like a human being than a machine. E.g.:
void TestFunction(int argument1, int argument2,
int argument3);
void TestFunctionVeryLongName(int argument1,
int argument2,
int argument3);
void TestFunctionWithRidiculouslyLongName(
int argument1, int argument2, int argument3);
Vim will definitely do this, although the results may not be perfect:
First, select the entire file in visual mode: ggVG
Then hit = to reindent everything.
You can learn more about the equal command with: :help =
There is also a Vim plugin relying on clang-format: vim-clang-format
Then you can simply map the formatting command to whatever suits you.
There is a vim plugin that enables formatting on your code from within vim. It's called vim-autoformat and you can download it here:
https://github.com/vim-autoformat/vim-autoformat
It integrates external code-formatting programs into vim. For example, if you want to format C, C++, C# or Java code, you need to install the program astyle, and vim sets it as the format program automatically.
I don't write C++ code, but I write some Java code.
Instead, Vim supports the formatting of some common languages.
I have set up a short cut for me to format the whole code in the buffer.
It will return to the line I just edited :)
" format the file
map <leader>fm gg=G'.
A generic solution along the lines of m000's idea is to use UniversalIndentGUI as an external tool.
Just had to solve this exact problem, so I thought I'd contribute to save others some time.
You can use gg=G to indent your code. But things get hard to understand the moment you want to tweak how that auto-indenting happens. Therefore, if you only care that errant whitespace is removed and don't really care about formatting style, gg=G is the quickest way to go about it, because its built-in.
If you do want to control the style (for example, you're trying to make your code conform to a style guide), then you're going to need an external tool to process your file. You can invoke that tool from within vim with: :%!<toolname> <options>. This pipes the file through the tool and re-loads the processed result. (You can obviously use this for anything else you want to do to your file too)
So the next question is, what external tool should you choose? Regardless, the method is the same:
Install the tool of choice
Make sure its in your path
Add a line to your vimrc file that creates a shortcut key to use so you save time
Use it.
Now, which tool you use depends on the style you're trying to replicate. If you're trying to replicate a widely used style, then chances are astyle is all you need.
If you're trying to replicate a custom style, then you will need two things:
UniversalIndentGui - a front end that lets you play around with various options and live-preview their effect on the source file
A set of source code formatting tools installed and in your path
Between uncrustify and greatcode, you should be able to completely replicate the style you want.
Actually, I lied. There is another way and its called clang-format. However, you're going to want to read the documentation on it and its still in early stages so some options don't work very well. It is a beautiful tool though (definitely the smartest of the lot because constructs an AST of your code) and it is even available for Windows.
If you're going to take the time to read the manual, you also want to check out GNU Indent.
Of course, there is the last way, which is actually taking the time to learn vim's indent rules and writing one for your style. It will take time, but it will work with gg=G.
Some notes on astyle vs uncrustify vs greatcode:
Astyle is good for general formatting, but can't do things like align the declaration of variables and re-style comments very well.
Uncrustify can do a LOT of stuff that astyle can't, but be prepared to spend an hour playing around until you've found the correct combination of options you need. (Or if you feel like wasting a lot of time, use genetic algorithms to figure out the best combination of options for your style and when you do share the code and give me a link so I can use it too :) )
Note that you don't have to choose one tool. With vim, you can map one keystroke to execute several commands in succession, so theoretically you could use a combination of these tools to get exactly what you're looking for.
Last but not least, here's an excerpt from my .vimrc file, where I have mapped F12 to invoke astyle with some options:
"A2 = attached brackets
"-s8 indent 8 spaces
"-xc attached braces to class declarations
"-xj remove braces for single statement ifs and elses
"-c convert tabs to spaces in the non-indentation part of the line
map <F12> :%!astyle -A2 -s8 -xc -xj -c<CR>
Don't judge me on the style. Just use the tool to reproduce what you want.

Resources