in vim, how to combine ^] and arge, to follow a tag and also add it to the arg list? - vim

I can get the word under the cursor with or , and I can use that to open a file and add it to the arg list. For example, with the cursor over a java class name, at line 45:
:arge +45 mydirhere/<cword>.java
But I don't know how to pass into the the tag mechanism, so it will return the file name (and line number), that can be passed to arge
So I guess my question is specifically: "how do you call the tag mechanism?" I'm expecting something like:
String getFileAndLineforTag(String tag)

You can use the taglist() function. From :help taglist() (in Vim 7.1):
taglist({expr}) *taglist()*
Returns a list of tags matching the regular expression {expr}.
Each list item is a dictionary with at least the following
entries:
name Name of the tag.
filename Name of the file where the tag is
defined. It is either relative to the
current directory or a full path.
cmd Ex command used to locate the tag in
the file.
kind Type of the tag. The value for this
entry depends on the language specific
kind values. Only available when
using a tags file generated by
Exuberant ctags or hdrtag.
static A file specific tag. Refer to
|static-tag| for more information.
More entries may be present, depending on the content of the
tags file: access, implementation, inherits and signature.
Refer to the ctags documentation for information about these
fields. For C code the fields "struct", "class" and "enum"
may appear, they give the name of the entity the tag is
contained in.
The ex-command 'cmd' can be either an ex search pattern, a
line number or a line number followed by a byte number.
If there are no matching tags, then an empty list is returned.
To get an exact tag match, the anchors '^' and '$' should be
used in {expr}. Refer to |tag-regexp| for more information
about the tag search regular expression pattern.
Refer to |'tags'| for information about how the tags file is
located by Vim. Refer to |tags-file-format| for the format of
the tags file generated by the different ctags tools.
When you define a custom command you can specify -complete=tag or
-complete=tag_listfiles. If you need to do something more elaborate you can use -complete=custom,{func} or -complete=customlist,{func}. See :help :command-completion for more on this.

Here's some code to do it though not going to the right line, using Laurence Gonsalves's answer (thanks!)
:exe "arge " . taglist(expand("<cword>"))[0].filename
A confusing part was how to integrate the worlds of functions and ordinary commands, which is done with ("exe") and string concatention (".")

Related

How to create a centralized syntax file that be able to recognize multiple parts with different syntaxes?

For i.e: I'd like to have a custom syntax file, may be called sugar.vim that includes multiple other syntax files(?) to have the ability to highlight, maybe a paragraph as python.vim and another paragraph as javascript.vim, may be separated by newline (paragraphs often distinct by newline)
The real case that I often catch myself writing a document (non-extension file) other than real config a specific filetype (specific extension file), but for clear readability in the document filetype (we called sugar above). I'm thinking about a mechanism to recognize and highlight different parts of a filetype as different syntaxes.
To narrow down this case. How would it be to have a syntax file called sugar.vim that would be able to recognize python syntax and javascript syntax in files that have an extension of .sugar then the recognized python text should have highlights applied as a normal python file, same for javascript part. All recognized text must be separated by newline (at least one before and one after that text)
Sample:
# this is a sample text for this question
# i'm writing a document that has an extension of `.sugar`
def py_func1(arg1, arg2) # python.vim and its highlights applied here.
print("bello world!")
square = function(x) { # javascript.vim and its highlights applied here.
return x * x;
};
System: gvim 8.1 / windows10
Thanks in advances.
Vim supports that with the :help :syn-include command. As it's intended for syntax script writers leveraging other syntaxes, its use is somewhat complicated, and it's not really suited for interactive, on-demand use.
My SyntaxRange plugin provides commands and functions to set up regions in the current buffer that either use a syntax different from the buffer's 'filetype', or completely ignore the syntax. With it, it's trivial to dynamically add a particular syntax highlighting for a range of lines, and public API functions also make the programmatic definition easier.
You're looking for :help :syn-include.
Excerpt from vim help :
If top-level syntax items in the included syntax file are to be
contained within a region in the including syntax, you can use the
":syntax include" command:
:sy[ntax] include [#{grouplist-name}] {file-name}
All syntax items declared in the included file will have the
"contained" flag added. In addition, if a group list is specified,
all top-level syntax items in the included file will be added to
that list. >
" In perl.vim:
:syntax include #Pod :p:h/pod.vim
:syntax region perlPOD start="^=head" end="^=cut" contains=#Pod
When {file-name} is an absolute path (starts with "/", "c:", "$VAR"
or "") that file is sourced. When it is a relative path
(e.g., "syntax/pod.vim") the file is searched for in 'runtimepath'.
All matching files are loaded. Using a relative path is
recommended, because it allows a user to replace the included file
with his own version, without replacing the file that does the ":syn
include".
As long as you can clearly define boundaries for your embedded language regions it is fairly straight forward to achieve this.
You can also refer to https://github.com/tpope/vim-markdown/blob/master/syntax/markdown.vim for reference on how tpope embeds other syntax definitions within the markdown syntax, driven by configuration to minimise the number of language syntax's that need embedding for optimal performance.

How to autocomplete in vim based off partial matching via ctags

Example:
In a file in another directory I have a function defined by the following:
def _generator_function_1(self):
passs
In the file of my current directory, I have typed the following:
def test_generI
where I denotes my cursor position.
I would like to use vim's autocompletion functionality (i.e. via ^n or ^p) to autocomplete the function definition to test_generator_function_1. Is there a way of configuring vim autocompletion to match not based off full-prefixes? Or, is there a way in ctags to generate tags based off keywords instead of full function definitions?
EDIT:
To clarify, I am specifically wondering if keyword-based autocompletion exists. I have autocompletion by tags setting up, so if I typed "_gen", then ^n would complete to give me "_generator_function_1". In my example, however, it is because the string is prefixed by "test" that "test_gener" as the starting typed word does not lead to any autocomplete suggestions. So I am wondering if this can somehow be made possible.
Vim doesn't have "autocompletion functionality". It only has "completion", not "autocompletion". You need a plugin for "autocompletion".
No, there's no way to obtain your desired behavior without some serious vimscripting. See :help complete-functions.

Vim: Substitute only in syntax-selected text areas

The exact problem: I have a source in C++ and I need to replace a symbol name to some other name. However, I need that this replace the symbol only, not accidentally the same looking word in comments or text in "".
The source information what particular language section it is, is enough defined in the syntax highlighting rules. I know they can fail sometimes, but let's state this isn't a problem. I need some way to walk through all found occurrences of the phrase, then check in which section it is found, and if it's text or comment, this phrase should be skipped. Otherwise the replacement should be done either immediately, or by asking first, depending on well known c flag.
What I imagine would be at least theoretically possible is:
Having a kinda "callback" when doing substitution (called for each phrase found, and requesting the answer whether to substitute or not), or extract the list of positions where the phrase has been found, then iterate through all of them
Extract the name of the current "hi-linked" syntax highlighting rule, which is used to color the text at given position
Is it at all possible within the current features of vim?
Yes, with a :help sub-replace-expression, you can evaluate arbitrary expressions in the replacement part of :substitute. Vim's synID() and synstack() functions allow you to get the current syntax element.
Luc Hermitte has an implementation that omits replacement inside strings, here. You can easily adapt this to your use case.
With the help of my ingo-library plugin, you can define a short predicate function, e.g. matching comments and constants (strings, numbers, etc.):
function! CommentOrConstant()
return ingo#syntaxitem#IsOnSyntax(getpos('.'), '^\%(Comment\|Constant\)$')
endfunction
My PatternsOnText plugin now provides a :SubstituteIf command that works like :substitute, but also takes a predicate expression. With that, it's very easy to do a replacement anywhere except in comments or constants:
:%SubstituteIf/pattern/replacement/g !CommentOrConstant()

Looking for a way to correctly order ctags matches

I have a codebase that has ctags configured correctly. When I do, :tjump keyword it shows me a list of potential matches for the keyword.
However these matches aren't ordered correctly. I'm looking for a way to correctly order the matches so that the best match is at the top of the list. ie:- the first jump when I directly use Ctrl-] should go to the correct place.
For the GetFile navigation with gf I have found includeexpr which allows me to run custom logic to determine the file to jump to.
Does Vim have a similar function for altering the tags results?
Another approach I am considering is to grab the list of tags from :tjump, do sorting, and override the mapping for Ctrl-].
For this approach, is there a function to get the list of matches from :tjump?
Any other ideas to ensure that the the correct match is at the top are also welcome!
Thanks.
It's often not clear what the "correct" match is. Currently Vim uses the following logic (from :help tag-priority):
When there are multiple matches for a tag, this priority is used:
1. "FSC" A full matching static tag for the current file.
2. "F C" A full matching global tag for the current file.
3. "F " A full matching global tag for another file.
4. "FS " A full matching static tag for another file.
5. " SC" An ignore-case matching static tag for the current file.
6. " C" An ignore-case matching global tag for the current file.
7. " " An ignore-case matching global tag for another file.
8. " S " An ignore-case matching static tag for another file.
If you want to implement your own custom logic, there's nothing (that I know of) similar to the includeexpr that can help you.
You could create multiple tags and order them in the tags setting in such a way that encodes your preference. It's hard to say what that would be, though, and very likely to require some experimenting.
Another, more complicated thing you could do is override the <c-]> key (and maybe others, like <c-w>]) to do something different. Something like:
nnoremap <c-]> :call <SID>JumpToTag()<cr>
function! s:JumpToTag()
" try to find a word under the cursor
let current_word = expand("<cword>")
" check if there is one
if current_word == ''
echomsg "No word under the cursor"
return
endif
" find all tags for the given word
let tags = taglist('^'.current_word.'$')
" if no tags are found, bail out
if empty(tags)
echomsg "No tags found for: ".current_word
return
endif
" take the first tag, or implement some more complicated logic here
let selected_tag = tags[0]
" edit the relevant file, jump to the tag's position
exe 'edit '.selected_tag.filename
exe selected_tag.cmd
endfunction
You can use the taglist() function to locate the tags for the word under the cursor. Then, instead of let selected_tag = tags[0], you can implement your own logic, like filtering out test files, or sorting by certain criteria.
Unfortunately, this doesn't maintain the :tnext and :tprevious commands, since you're manually editing files. You could replace it with the quickfix or the location list, using the setqflist() function with the tags ordered the way you like and then navigate using :cnext and :cprev. But that's a whole lot of more scripting :). If you decide to go down this rabbit hole, you might want to take a look at the source of my tagfinder plugin for inspiration.
Based on your comment to #AndrewRadev's answer:
I often create a "mktags" script that builds ctags and then filters out of the tags file the ones I want to omit. For example (for sh, ksh, bash, zsh):
ctags "$#"
egrep -v "RE-for-tags-to-delete" tags > tags.$$
mv tags.$$ tags

How to delete text in a file based on regular expression using vim

I have an XML file like this:
<fruit><apple>100</apple><banana>200</banana></fruit>
<fruit><apple>150</apple><banana>250</banana></fruit>
Now I want delete all the text in the file except the words in tag apple. That is, the file should contain:
100
150
How can I achive this?
:%s/.*apple>\(.*\)<\/apple.*/\1/
That should do what you need. Worked for me.
Basically just grabbing everything up to and including the tag, then backreferences everything between the apple begin and end tag, and matches to the rest of the line. Replaces it with the first backreference, which was the stuff between the apple tags.
I personally use this:
%s;.*<apple>\(\d*\)</apple>.*;\1;
Since the text contain '/' which is the default seperator,and by using ';' as sep makes the code clearer.
And I found that non-greedy match #Conspicuous Compiler mentioned should be
\{-}
instead of "{-}" in Vim.
However, I after change Conspicuous' solution to
%s/.*apple>(.\{-\})<\/apple.*/\1^M/g
my Vim said it can't find the pattern.
In this case, one can use the general technique for collecting pattern matches
explained in my answer to the question "How to extract regex matches
using Vim".
In order to collect and store all of the matches in a list, run the Ex command
:let t=[] | %s/<apple>\(.\{-}\)<\/apple>\zs/\=add(t,submatch(1))[1:0]/g
The command purposely does not change the buffer's contents, only collects the
matched text. To set the contents of the current buffer to the
newline-separated list of matches, use the command
:0pu=t | +,$d_

Resources