Color scheme based on distro name [linux] - linux

I use the same vim setting across multiple Linux systems (at the moment Kubuntu and OpenSuse) thanks to git. I want to use different color schemes in for the various distros.
So I've create a plugin plugin/mycolor.vim where I fetch the distro name from /etc/os-release and then use
if s:distro ==? "openSUSE"
blabla
else
blabla2
endif
The /etc/os-release looks like
NAME="Ubuntu"
VERSION="13.04, Raring Ringtail"
[...]
or
NAME=openSuse
VERSION="13.1 (Bottle)"
The shortest way to get the distro name that I have found (with some help) is
let distro = system(". /etc/os-release; echo -n $NAME")
but the idea of sourcing the file make be a bit uneasy, although it seems that the sourcing does not propagate outside the call of system.
The other, longer and probably safer way, that I've found is:
let s:distro = system("awk '/^NAME=/ {print $1}' /etc/os-release")
let s:distro = split(substitute(s:distro, "\n", "", ""), "=")[1]
let s:distro = substitute(s:distro,'"', "", "g")
The first line gets all the line containing NAME= included the new line character. The second line remove the new line and return the part after =. The third line removes the " if any.
Is that any better way to get the distro name or is already stored in some vim variable?

As Vim is multi-platform, it tries to avoid platform-specific stuff as much as possible. Therefore, there's no built-in variable; you can only use has('unix') to check for a Unixoid operating system in general.
I'd use your first approach with sourcing /etc/os-release (calling lsb_release -is might work, too); as it only invokes the shell, it's probably a tiny bit more efficient than using AWK to parse. You could also read in the file in Vimscript (via readfile()) and do the parsing there, but that just adds additional dependencies to the used syntax.
As a new shell is launched for system(), this has no side effects in Vim. Also, since the data file resides under /etc, only users with administrative rights are able to change it, so it's no security risk.
Alternative
If you have a need for other system-specific Vim configuration (e.g. different window size, or font), an elegant way is to add the following to your ~/.vimrc:
" Source system-specific .vimrc first.
if filereadable(expand('~/local/.vimrc'))
source ~/local/.vimrc
endif
In that local config file, you can then define a g:distro config variable. This duplicates the actual information and requires a bit of manual setup, but would avoid the system call on each Vim startup.

If you want to have different setting for different computer/system, I am with Ingo. create its own config part, and in your common vimrc source the specific config. I manage my .zshrc in this way among three computers.
If you just want to get the string from /etc/os-release, you could try:
let dis = system("awk -F= '$1==\"ID\"{printf $2}' /etc/os-release")
here it prints arch (I am running on archlinux). I picked ID instead of NAME because the NAME could have spaces.
If you like you can try to process the file /etc/issue, if all your systems have that file.

Related

Perforce Line Endings per file

My Perforce-based project supports both Linux and Cygwin platforms with the same shell scripts (e.g. build_project.sh). But Perforce defaults line endings for text files to the local platform (Docs). This causes \r\n newlines in the .sh scripts, which fail on Cygwin.
Some of the ideas I've thought of so far:
Is there a way to make Cygwin accept \r\n files? (Without having to run dos2unix, the files fetch as read-only).
Is there a way to set specific files to be text, but with Unix line endings for everyone? (I am guessing, "no", but thought I'd check.)
Of course I can set the entire workspace's line endings to \n (unix). But this makes the Windows clients unhappy with their .bat files being \n instead of \r\n. Also if the setting is per workspace (I can't recall), then a workspace setup is slightly harder for the new Windows user as they must set that option.
Set the .sh files to be "binary", but then we lose the text diffs on those files. Is there a workaround for this? Is this the common (good) hack?
This is a fairly minor nit, but I suspect that some of you have a BKM for this pattern.
Thanks.
EDIT: Craig's answer in this question seems to suggest that using Unix line endings will just leave files with \r\n's alone if they are originally submitted that way.
EDIT: To force bash (i.e. Cygwin) to accept files with \r\n endings, one can specify set -o igncr in the script. This is nice if one expects Cygwin users to that might not be very Unix literate (my case) or when we can't globally impose the trigger in the solution below for some other reason.
I believe that when you install Cygwin you can configure it to use Windows line endings. Leaving that aside, though:
If you use the "unix" LineEnd for absolutely everyone, then all of your text files will have their own internally-consistent line endings (but will not be necessarily consistent with the client platforms). This works by virtue of the fact that the Windows files will end up having the \r as part of the content of the line, so when being synced out in "unix" format they'll have \r\n endings.
The thing to watch out for is mixing and matching LineEnd settings when doing this -- if somebody with a "win" or "local" LineEnd syncs that same file, now they have \r\r\n endings! So if you want to go with the per-file line ending plan, make sure EVERYONE uses "unix" as their LineEnd. This is pretty easy to do with a trigger, e.g.:
Triggers:
form-in client "sed -i %quote%s/LineEnd:.*/LineEnd: unix/%quote% %formfile%"

conflict in configuration file paths between Linux and Windows

I have this line in my .vimrc file:
set directory=~/.vim/swapfiles//
(Note that one extra slash makes the directory names to be included instead of just file names to reduce conflict)
The above config works fine on my Linux machine, but the problem is when I use the same file on Windows I get some warning about the file cannot be read. That's probably because vim is looking for ~/.vim/swapfiles/ directory, which Windows unfortunately don't have.
Is there any way to store my swap files on Windows somewhere (better if it could be in C:\Program Files\Vim\vimfiles\)?
CASE #2
If you got answer for my above question, here is the another one. I also have some lines similar to this:
autocmd filetype python source ~/path/to/file/python.vim
Windows confuses at this point too. How can I patch up?
If you don't want to introduce a $MYVIM variable as ZyX suggests, maybe an alternative is placing the runtime files in $HOME/.vim instead of the default $HOME/vimfiles on Windows. You can then use ~/.vim/... everywhere. This also helps with synchronizing the files across multiple mixed-platform machines.
" On Windows, also use '.vim' instead of 'vimfiles'; this makes synchronization
" across (heterogeneous) systems easier.
if has('win32') || has('win64')
set runtimepath=$HOME/.vim,$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after,$HOME/.vim/after
endif
Maybe what you want is to have directory set based on the entries in runtimepath? Try this:
let &directory = substitute(&rtp, ",", "/swapfiles//,", "g")
With the default runtimepath setting on Unix-y systems you get
$HOME/.vim/swapfiles//,
$VIM/vimfiles/swapfiles//,
$VIMRUNTIME/swapfiles//,
$VIM/vimruntime/after/swapfiles//,
$HOME/.vim/after//
and on Windows
$HOME/vimfiles/swapfiles//,
$VIM/vimfiles/swapfiles//,
$VIMRUNTIME/swapfiles//,
$VIM/vimfiles/after/swapfiles//,
$HOME/vimfiles/after/swapfiles//
I agree, the after directories are unwanted, but vim will pick the first directory that exists and allows file creation so if you don't create the swapfiles sub-directory they won't be touched.
You might want to consider prepending these to the default value instead of replacing it so the defaults are available as a fallback if none of the directories exist.
I don't understand why you have the auto commands you mention. The default settings of runtimepath with filetype plugin on should take care of that for you.
Of course you always have the option of explicitly checking the platform and using different settings as in
if has("win32")
" settings for windows
elif has("win32unix")
" settings for cygwin
elif has("unix")
" settings for unix
elif has("macunix")
" settings for macosx
endif
If you want to avoid an error if a file does not exist then you can use the following definitions in your vimrc
func! Source(file)
if filereadable(a:file)
exec "source " . fnameescape(a:file)
endif
endfunction
com! -nargs=1 -complete=file Source call Source(<f-args>)
and change source to Source when the file might not exist.
First of all, vim translates all forward slashes to backward on windows thus it won’t hurt having slashes. Just in case you think it can be a source of trouble.
Second, it is not impossible to have ~/.vim and all other directories on windows, just some programs don’t want to work with names that start with a dot. You may just add this to runtimepath as it is not there by default on windows and move all user configuration there.
Third, in most places you have a filename you may use $ENV_VAR. It includes setting &rtp, &directory and using :source. So the solution may be the following:
if has('win16') || has('win95') || has('win32') || has('win64')
let $MYVIM=$HOME.'/vimfiles'
else
let $MYVIM=$HOME.'/.vim'
endif
set directory=$MYVIM/swapfiles
autocmd FileType python :source $MYVIM/after/ftplugin/python.vim
(though I agree with #Geoff Reedy that there should be no need in using the last line).
And last, modifying and storing something in C:\Program Files is not the best idea, neither for you nor for the program itself (by the way, vim won’t modify or store something there unless you told it to). It is to be modified by installation, update and uninstallation processes, not by anything else.
I fully agree with Geoff Reedy that the autocmd shouldn't be necessary. In other cases, you can use :runtime instead of :source. It will automatically search all (user and system directories in 'runtimepath'.

GVim: find out if guifont is available

I'm sharing my vim settings across a number of different machines, which don't neccessarily have exactly the same configuration.
Now if my favourite font is only available on one system but not another, this leads to the problem that gvim uses a fallback which may not be the best choice.
So: Is there a way to do multiple tries of set guifont=... and somehow check whether it was successful? Or is there a way to provide a list of fonts to try?
You can give Vim a list of fonts:
set guifont=Monaco:h24,Inconsolata-gz:10
Vim will try the first then the second…
:h guifont doesn't tell if there's a limit to the number of choices.
Detection / fallbacks may work in this instance, but things get hairy when you also want different font sizes (due to different display resolutions), window sizes, local commands, etc.
A more extensible system than switching on $HOSTNAME or similar schemes is checking for a "local" .[g]vimrc and sourcing that in:
" Put this in ~/.gvimrc:
" Source system-specific .gvimrc first.
if filereadable(expand('~/local/.gvimrc'))
source ~/local/.gvimrc
endif
This way, all special settings are localized and do not complicate your shared config.
Following the accepted answer is likely the right method in most cases, but this is a work around. Platform specific to unix like gtk2 systems only. First, create a function checking for the font using a shell command:
function! Font_exists(font)
exec system("fc-list -q '" . a:font ."'")
return v:shell_error == 0
endfunction
Then use it with whatever logic is desired. E.g.:
if Font_exists('Iosevka Term')
set guifont=Iosevka\ Term\ Light\ 9
elseif Font_exists('Inconsolata')
set guifont=Inconsolata\ 9
elseif Font_exists('Terminus (TTF)')
set guifont=Terminus\ (TTF)\ 9
endif

Use Vim to "colourize" files or input streams

This may be an odd question, but still. I use cat to display a file in bash (KDE Konsole),
cat foobar.rb
Now, I would like to use Vim to colourize that foobar.rb file according to what you would get when you start foobar.rb in Vim. Edit: But only for display purpose, on the terminal.
I am not sure this is possible, but I thought it would be neat if I could use Vim for that.
I really just want colourized keywords, and Vim has the perfect colour definitions.
So I thought combining this would be great.
Is this possible in Vim out of the box though?
One approach would be to use a library such as Pygments, which is a general purpose syntax highlighter. You could write a wrapper called ccat or something that would apply syntax highlighting to an input file and write to stdout.
If you want to page up and down in a highlighted file, you can use less with the -R switch, which passes control characters through to the terminal directly, preserving colours. So:
ccat file.rb | less -R
But at that point, you're pretty much at the capabilities of view.
I'm not sure if I understand your question correctly, but if you are only looking for a command that will give you a read-only view of the input file (like cat) but with coloured keywords, use view. view is an alternative way to start vim in read-only mode, so you have all syntax highlighting possibilities. From the vim man page:
view Start in read-only mode. You will be protected from writing
the files. Can also be done with the "-R" argument.
gvim gview
The GUI version. Starts a new window. Can also be done with
the "-g" argument.
evim eview
The GUI version in easy mode. Starts a new window. Can also
be done with the "-y" argument.
rvim rview rgvim rgview
Like the above, but with restrictions. It will not be possi-
ble to start shell commands, or suspend Vim. Can also be
done with the "-Z" argument.
I have always seen view on systems that have vim installed.
Closest is the less script that comes with vim:
cat myfile | vim -u /usr/share/vim/vim72/macros/less.vim -
Note the - argument to vim. You may need to change the vim72 to your version (and the whole path if you have it installed elsewhere)
Now, this isn't exactly what you want, because its behaviour is less-like, in that you have to press keys to make it scroll down or complete. However, they are briefer than usual vim. For example, space to scroll down; and q to quit (not :q).
You want a cat-like version; me too. But there doesn't seem to be one.
EDIT uh, there's also a vimpager project, that includes vimcat - exactly what you want. But it doesn't come with vim, and I haven't tried it yet.
vim.org: http://www.vim.org/scripts/script.php?script_id=1723
github: https://github.com/rkitover/vimpager

How to switch between multiple vim configurations with a command or local vimrc files?

I work in several groups, each of which has its own tab/indentation/spacing standards in C.
Is there a way to have separate selectable VIM configurations for each so, when I edit a file, either:
I do something like set group=1 to select a configuration
a local .vimrc that lives in the working directory is used to set the configuration automatically
I have this in $HOME/.vimrc:
if filereadable(".vim.custom")
so .vim.custom
endif
This allows me to put a .vim.custom file in every directory to load commands and options specific to that directory. If you're working on multiple projects that have deep directory structures you might need something more sophisticated (e.g. walk up the directory tree until a .vim.custom is found), but the same basic idea will work.
UPDATE:
I now do something like this in order to read a .vim file from the same directory as the file I'm editing, regardless of what the current directory is.
let b:thisdir=expand("%:p:h")
let b:vim=b:thisdir."/.vim"
if (filereadable(b:vim))
execute "source ".b:vim
endif
In Summary
There are a few ways to do this, of which most have been suggested, but I thought I'd summarise them with two extra ones:
Per-directory vimrc - has the disadvantage that Vim must be started in the right directory: if your project is in ~/project1 and you have ~/project1/.vim.custom and do cd ~ ; vim project1/file.c, the custom settings won't be found.
Modelines - very effective, but has the disadvantage of needing to add them to all files (and remember to add them to new files)
Directory specific autocommands - this is very effective
Scan for a specific header in the file (see below) - this is the one I've used most in the past where working for different companies or on clearly named projects
Per-directory vimrc that's checked when the file is opened (see below). Another fairly easy one to implement, especially if your project code is all in one place.
Scanning for a Header
In a lot of organisations, there's a standard header (with a copyright notice and project name etc) at the top of every source file. If this is the case, you can get Vim to automatically scan the first (e.g.) 10 lines of the file looking for a keyword. If it finds it, it can change your settings. I've modified this to make it simpler than the form I use (which does lots of other things), but create a ~/.vim/after/filetype.vim (if you don't have one yet) and add something like this:
au FileType * call <SID>ConfigureFiletypes(expand("<amatch>"))
" List of file types to customise
let s:GROUPNAMETypes = ['c', 'cpp', 'vhdl', 'c.doxygen']
func! <SID>CheckForGROUPNAMECode()
" Check if any of the first ten lines contain "GROUPNAME".
" Read the first ten lines into a variable
let header = getline(1)
for i in range(2, 10)
let header = header . getline(i)
endfor
if header =~ '\<GROUPNAME\>'
" Change the status line to make it clear which
" group we're using
setlocal statusline=%<%f\ (GROUPNAME)\ %h%m%r%=%-14.(%l,%c%V%)\ %P
" Do other customisation here
setlocal et
" etc
endif
endfunc
func! <SID>ConfigureFiletypes(filetype)
if index(s:GROUPNAMETypes, a:filetype) != -1
call <SID>CheckForGROUPNAMECode()
endif
endfunc
Whenever a file of any type is opened and the file type is set (the au FileType * line), the ConfigureFiletypes function is called. This checks whether the file type is in the list of file types associated with the current group (GROUPNAME), in this case 'c', 'cpp', 'vhdl' or 'c.doxygen'. If it is, it calls CheckForGROUPNAMECode(), which reads the first 10 lines of the file and if they contain GROUPNAME, it does some customisation. As well as setting expandtabs or whatever, this also changes the status bar to show the group name clearly so you know it's worked at a glance.
Checking for Configuration When Opening
Much like JS Bangs' suggestion, having a custom configuration file can be useful. However, instead of loading it in vimrc, consider something like this, which will check when a .c file is opened for a .vim.custom in the same directory as the .c file.
au BufNewFile,BufRead *.c call CheckForCustomConfiguration()
function! CheckForCustomConfiguration()
" Check for .vim.custom in the directory containing the newly opened file
let custom_config_file = expand('%:p:h') . '/.vim.custom'
if filereadable(custom_config_file)
exe 'source' custom_config_file
endif
endfunction
You can also put autocommands in your .vimrc which set specific options on a per-path basis.
au BufRead,BufNewFile /path/to/project1/* setl sw=4 et
au BufRead,BufNewFile /path/to/project2/* setl sw=3 noet
Plugin doing the right thing:
http://www.vim.org/scripts/script.php?script_id=441
“This plugin searches for local vimrc files in the filesystem tree of the currently opened file. By default it searches for all ".lvimrc" files from the file's directory up to the root directory and loads them in reverse order. The filename and amount of loaded files is customizable through global variables.”
Assuming your fellow developers won't complain about it, you can always add vim settings to each file in the comments.
/*
* vim:ts=4:sw=4:expandtab:...
*/
int main(int argc, char **argv)
{
...
I created an open-sourced tool for just this purpose. Forget the headers, scanning, configurations, and local vimrc files.
Try swim.
Swim
swim is a quick tool for switching vimrc files and creating convenient aliases. Here's a short usage list. See the Github repo for a walkthrough gif and download instructions:
Usage
swim add ~/dotfiles/myVimrc favorite #Add new swim alias
swim ls #Show available swim aliases
swim add https://raw.githubusercontent.com/dawsonbotsford/swim/master/exampleVimrcs/vimrcWikia.vim example
swim with favorite #Set alias favorite as primary .vimrc
swim with main #Set alias main as primary .vimrc
Read More
https://github.com/dawsonbotsford/swim
After trying out the localvimrc plugin suggested by the previous poster, I very much like having non-futzy per-project control over vim settings.
It does ask confirmation before loading a .lvimrc file by default but there is a setting to automatically load .lvimrc files. Some might see this as a security hole, but it works as advertised.
I chose to .gitignore the .lvimrc files. Alternatively you can check them in as a form of shared settings (tab/space expansion, tabstops, other project-specific settings).
As mentioned by sledge the usage of that plug-in is the best option I have seen and use. jerseyboy commented that the utility recommended ask for confirmation before loading (ie. after opening every file). To avoid this just set at your main .vimrc the list of local .lvimrc files:
let g:localvimrc_whitelist='/development/kernel/.lvimrc'
Here's a variation on jamessan's
function! ConditionalLoad()
let cwd = getcwd()
if getcwd() =~ $HOME . "/src/mobile"
so $HOME/.vim.mobile
endif
endfunction
autocmd VimEnter * call ConditionalLoad()
I will frequently launch vi without a specific file that I'm jumping to so this enables loading config conditionally based on the current working directory. Downside is that the config isn't applied based on file but off of working directory.
I work in several groups, each of which has its own tab/indentation/spacing standards in C.
I work with all sorts of open source, all at the same time. It's not practical to be creating separate .vimrc files and reconfiguring the formatting standards. More than a decade ago, I finally got tired of dealing with the editor configuration and wrote a program called autotab to handle it.
When autotab is set up with Vim suggested, each time you load a file into Vim, autotab is invoked on it, and the Vim settings output autotab are passed to a :set command.
autotab reads several thousand lines from the file, analyzes them and determines the settings for the expandtab, tabstop and shiftwidth parameters.
It figures out whether the file uses hard tabs or just spaces for indentation, and it figures out the indentation size. If the file is indented with tabs, it figures out the right tab size, based on rendering the file sample using various tab sizes and judging it according to heuristics like line-over-line alignment of internal elements.
It works well enough that I stopped tweaking the algorithm years ago. If it gets confused, it's almost always because the file has formatting issues, such as the use of multiple conventions at the same time.
It is also "agnostic" of the file type and works well with a variety of different languages. I use it not only over C, but shell scripts, Lisp, Makefiles, HTML, and what have you.
Note that it doesn't handle other parameters of formatting that may be project-specific, like for instance, in C files, whether case labels in a switch statement are indented or not, or whether wrapped function argument lists are simply indented, or aligned to the opening parenthesis of the argument list. Vim does have settings for that sort of thing, and so the program could be plausibly extended to analyze the style and output those parameters.
Looking for mostly the same issue I also found the Sauce plug-in: http://www.vim.org/scripts/script.php?script_id=3992
It claims:
Sauce is a lightweight manager for multiple vimrc files, which can be used to load different settings for different environments. In short, you can maintain lots of different vim settings files and only load the one(s) you need when you need them.
I find it particularly interesting that it keeps it configuration all in its data directory instead of expecting the user to sprinkle dotfiles across the filesystem. This though often rather a metter of personal taste.
I have yet to test it though.
You can use stow for switching configuration (any dotfiles, not only .vimrc)
Install stow:
$ apt install stow
Create multiple directories for each configurations:
~$ ls -d ~/dotfiles/vim*
vim-all vim-webdev vim-go
Put different .vimrc's in them:
$ find ~/dotfiles -name .vimrc
/home/username/vim-golang/.vimrc
/home/username/vim-webdev/.vimrc
/home/username/vim-all/.vimrc
Now you can instantinate vim-golang config with this command (should be run inside dotfiles directory):
~$ cd ~/dotfiles
dotfiles$ stow -v vim-golang
LINK: .vimrc => dotfiles/vim-golang/.vimrc
Now it's linked:
$ cd ~ && ls -l .vimrc
.vimrc -> dotfiles/vim-golang/.vimrc
If you need to switch config, just re-stow it:
~$ cd dotfiles
dotfiles$ stow -v -D vim-golang
UNLINK: .vimrc
dotfiles$ stow -v vim-webdev
LINK: .vimrc => dotfiles/vim-webdev/.vimrc
$ cd ~ && ls -l .vimrc
.vimrc -> dotfiles/vim-webdev/.vimrc
More reading of it here: Managing dotfiles with GNU stow
Pros: pretty simple, no vim plugin dependencies, can be used for managing all dotfiles, not only .vimrc.
Cons: configs are independent of each other, you need to manage/update each of them separately (if you dont switch/update you configs too often - it'll not be the issue).

Resources