How do I configure VIM to use different syntaxes in different parts of a file? - vim

I have a file that works like this:
:: JavaScript
function whatIsThis(){
return "an example";
}
:: Haskell
main = putStrLn "is this is an example?"
:: C
#include <stdio.h>
int main(){
printf("yes, it is");
};
In other words, a line starting with :: determines the syntax of the next lines until another :: is found. Is there any way to configure vim to highlight the syntax of those blocks correctly?

Have a look at my SyntaxRange plugin; it offers both a :[range]SyntaxInclude command, and functions to define regions (based on start and end patterns) to highlight with a particular syntax. For your example:
call SyntaxRange#IncludeEx('start="^:: Haskell" end="^::"me=e-3', 'haskell')
call SyntaxRange#IncludeEx('start="^:: C" end="^::"me=e-3', 'c')
call SyntaxRange#IncludeEx('start="^:: JavaScript" end="^::"me=e-3', 'javascript')

If you want to have full editing capabilities for each separate part (i.e. filetype-specific settings, customizations, mappings, commands), not just specific syntax highlighting, you won't get around having a separate buffer for each fragment (as these things are all tied to the buffer's filetype).
With the NrrwRgn - A Narrow Region Plugin similar to Emacs, you can cut up the original file into separate buffers (shown e.g. in split windows), and the plugin syncs any changes back to the original automatically.

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 script in Vim to yank only lines from a visual selection (or fold) that match a certain pattern?

I'd like to add a command to my .vimrc that allows to, within a visual selection or the range of the current fold level to
yank all, but only those lines that match a certain pattern.
and as a bonus to
reverse their order
and
perform a small pattern substitution.
Specifically the idea is to reduce the legwork in writing the common C idiom fail-goto-rollback, i.e. (can be found in lot of C projects most prominently the Linux kernel) if the body of a function (or a block) is this
someErrorType errorcode;
if(fail1) {
errorcode = someError1;
goto error_1;
}
prepare_a();
if(fail2) {
errorcode = someError2;
goto error_2;
}
then the result of the desired transformation shall be this.
error_2:
/* <insert cleanup code operation that did not fail1 here> */
error_1:
for the "yanking all", you can do:
normal mode: qaq to clear reg a
do visual selection
press :, vim will auto add '<,'>, then g/pattern/y A<Enter>
all your needed lines are in reg a, you can "ap to paste. for the reversing order requirement, I don't understand. What output do you expect. A concrete before/after example may help.
For adding boilerplate code, the usual solution is via a snippets plugin, which solves this (at least partially) in a generic way, instead of building a (possibly brittle) special solution with Vim built-ins.
snippets are like the built-in :abbreviate on steroids, usually with parameter insertions, mirroring, and multiple stops inside them. One of the first, very famous (and still widely used) Vim plugins is snipMate (inspired by the TextMate editor); unfortunately, it's not maintained any more; though there is a fork. A modern alternative (that requires Python though) is UltiSnips. There are more, see this list on the Vim Tips Wiki.
There are three things to evaluate: First, the features of the snippet engine itself, second, the quality and breadth of snippets provided by the author or others; third, how easy it is to add new snippets.

How to autocomplete c or c++ keywords in vim

For example, when I type 'inclu', is there a method which can complete it to 'include'?
Thank you.
Most of vim's (complex) auto-completion is done via the ^X key mapping. ^X^] will autocomplete based on tags generated by ctags(1). ^X^P looks for previous keywords in the file that can be used for completion. ^X^K looks into a configurable dictionary for completion words. ^X^I looks into included files and pops up a menu for completing keywords from within those files. ^X^D completes from #define.
Perhaps the simplest way to get what you're after is to fully type #include <...> once in your file. The second file to be included could then be handled via #incl^X^P and then keep going.
If you want to put slightly more effort into it, create a ~/.vim/dict file with the keywords you want to autocomplete, add the file to the dictionary variable (:help dictionary), and use ^X^K to insert it.
Maybe, any plugin like Snipmate or UltiSnips will be helpful for you.
You may want to try the Vim plugin Supertab. If you do, I suggest installing it using Pathogen.
Snipmate does this by default. type 'inc' and press Tab, it will convert into
#include <stdio.h>
You could set up some Vim abbreviations to do this for you.
iab inc #include ""
iab Inc #include <>
Then by typing inc<SPACE> Vim will automatically expand this to #include "". You could add all kinds of abbreviations to reduce the number of keystrokes required.
If you want to push this further, I'll share a little ongoing experiment of mine to create a C++ 'shorthand'. Though it certainly reduces the number of keystrokes required to input code, I haven't used this long enough to determine if the added mental complexity of remembering the shorthand is worth it. (Probably not!)
You will need to install UltiSnips for this to work. You could probably do most of this using Vim's abbreviation feature, but I've found it works best with a dedicated snippet completer.
Once UltiSnips is installed you will already have some C and C++ snippets ready to use, including the #include "" example mentioned above.
I've added the following (plus many, many more!) to my cpp.snippets file.
snippet sptr "std::shared_ptr< type >"
std::shared_ptr< ${1:type} >
endsnippet
When I want a shared_ptr I type sptr and press the snippet completion key. UltiSnips completes this as std::shared_ptr< type > with the word type selected so I can continue entering the template type without pausing.
This contrived example shows some more of the shorthand. This is what I could type:
// <C> is where I would press the UltiSnip complete/next key.
fun<C>sptr<C><C>load_widget<C>cu32<C>offset<C>, cc<C>name<C>ret<C>msptr<C>widget<C>offset<C>name<C>;
Which expands to:
std::shared_ptr< widget > load_widget( const std::uint32_t offset, const char* name )
{
return std::make_shared< widget >( offset, name );
}
A rough count shows this reduces approximately 136 keystrokes down to 100. With Omnicomplete or YouCompleteMe plugins, this is reduced further as variable and function names can often be completed after the first 2 or 3 characters have been entered.
I try to stick with this pattern when creating a shorthand for types: [c]type[r|p]. [c] is optional const, [r] or [p] for optional reference or pointer. (r and p and easier for my to type than & and *). For example, std::string has the following shorthand:
str = std::string
strp = std::string*
strr = std::string&
cstr = const std::string
cstrp = const std::string*
cstrr = const std::string&
So cstrr, the most common of these in my code, reduces 19 keystrokes (there's a trailing space) down to just 6.
you should install omni plugin: omni autocompletion

Is there a "verbatim" mode for the vim map command?

I am trying to set up some useful coding templates in vim, for example I have mapped
map `cl iclass <+CLASSNAME+><CR>{<CR><Esc>Iprotected:<CR><+PROTECTED MEMBERS+><CR><Esc>Ipublic:<CR><+PUBLIC INTERFACE+><CR>};<CR><++><CR><Esc>3kv<0v3k<2k
so that when I type `cl in vim I get
class <+CLASSNAME+>
{
protected:
<+PROTECTED MEMBERS+>
public:
<+PUBLIC INTERFACE+>
};
<++>
(so that I can jump between the <+ +> tags with C-j). This works fine, but I find the above remap pretty obscure. Is there a way to enter what I want vim to type in "verbatim mode"? So I would want to write something like
map `cl i{VERBATIMSTART}class <+CLASSNAME+>
{
protected:
<+PROTECTED MEMBERS+>
public:
<+PUBLIC INTERFACE+>
};
<++>{VERBATIMEND}
?
Thank you
Paul
I don't know if there is such a "verbatim"-mode for mappings.
I, personally, would use one of the snippet-plugins to do this.
See www.vim.org and search
for "snippet". I have not tried all of them (just SnippetsMgr ;-) ),
but I suppose that they are handier to define multi-line-snippets.
Some of the available snippet-plugins on vim.org: snippets.vim ,
snippetsEmu, snipMate, SnippetsMgr, etc.
As Habi has mentioned, one way to go about this is with a snippet plugin.
Another way is to copy that snippet of code into its own file and set up your mapping to insert that file below the cursor:
map `cl :r /path/to/code_snippet<CR>
Kind of obvious (and probably not what you want) is:
map `cl iclass <+CLASSNAME+>
\<CR>{
\<CR>protected:
\<CR> <+PROTECTED MEMBERS+>
\<CR>public:
\<CR> <+PUBLIC INTERFACE+>
\<CR>};
\<CR><++>
\<CR>
\ in beginning of line tells that the line is the continuation of the previous one. But this is rather literal continuation: it doesn't add new lines so one has to add them manually. Since it uses the insert mode, the operation would be also affected by the current indentation mode. (Though one can try to work that around with :set paste/:set nopaste.)
I would have tried to put the text into a temp variable or register then Pput (or :put) it into the buffer. E.g. setreg() allows one to tell that the content of a register are lines and thus Putting it would work regardless of indentation.
Otherwise, looking in :help line-continuation or :help variables I see no way how one can specify a multi-line string or text.

In VIM: How to highlight "local variables" in a "C" file

I have highlighted all Symbols by using tags file & highlight option.
But I could not able to highlight my local variables.
I have an idea, that is, VIM already supports autocompletion of keywords for a current file, it does autocompletion of my local variable, so, if I get a list of keywords for my current file then I will highlight those keywords by using "highlight" vim command.
But problems is, I don't know, how to get a list of keywords for a current file.
You can highlight recognised names using the tags file as long as the tags file is generated with the --c-kinds=+l to ensure that it includes local variables. However, there is currently no realistic way to identify the scope of those variables (ctags does not provide much information), therefore Vim will not distinguish between variables in one function and another:
void main(void)
{
int MyVariable; // Highlighted
}
int MyFunction(void)
{
int MyFunctionVariable; // Highlighted
MyVariable = 1; // Syntax error, but still highlighted
}
It could be done by parsing the C file in a little more detail and creating syntax regions for each function, but it is far from easy (and it would be incompatible with plugins like rainbow.vim as Vim doesn't support overlapping regions).
On a related note, you may also be interested in my tag highlighting plugin available here. It will highlight local variables (if b:TypesFileIncludeLocals is set to 1 in the buffer open when running :UpdateTypesFile), but it doesn't deal with the scope of local variables. It does, however offer a lot more highlighting colour variations than the highlighting suggested in :help tag-highlight. Note that your colour scheme will have to have highlights defined for lots of extra groups (e.g. GlobalVariable, LocalVariable, DefinedName etc) to take full advantage of it.

Resources