Vim: how to automatically highlight each line containing a keyword? - syntax-highlighting

if is a ".log" file, want to make every line containing keyword "dog" in the file to be in red, and make every line containing keyword "cat" in the file to be in yellow. This should be done automatically when I open a ".log" file in vim. Is there any way to do this?

First, define the colors as highlight groups:
:hi Dogs ctermbg=red guibg=red
:hi Cats ctermbg=yellow guibg=yellow
You can add (window-local) highlighting via the :match commands or the matchadd() function. By matching the entire line containing the keyword, you'll get all highlighted. The :autocmd installs that for your log files (though I would prefer to use Vim's filetype detection instead of hard-coding the file pattern).
:autocmd BufWinEnter *.log call matchadd('Dogs', '^.*dog.*$') | call matchadd('Cats', '^.*cat.*$')
The benefit of :match is that is doesn't interfere with syntax highlighting (which would be an alternative). The downside is that the highlighting will persist when you view a non-log buffer in the same window. (You can fix this by adding more autocmds, but it's not trivial.)

Related

Weird txt behavior

I have a centos server. I cloned a GitHub repository. And I have .txt file in that repository which contains 1 line. For some reason it does that:
[root#0-0-0-0 Some]# cat some.txt
some text[root#0-0-0-0 Some]#
And also while read i; do echo "$i"; done < some.txt don't see that line. What could cause that? And how to avoid it. If I edit it with vim adding a new line and then deleting that new line (so it still contains only one line) it starts to work properly.
The text file has no newline character at the end of it. Some programs will treat it as a valid text file whose last line doesn't happen to end in a newline. Others (apparently including bash's built-in read command, at least by default) will treat it as invalid, and perhaps ignore the last line (which isn't considered a "line" because it's not marked as one).
vim's default behavior is to quietly add a newline to the end of a file if you modify and save it.
You can add a newline to a file that lacks one by editing it with vim (or another editor that behaves similarly), or by adding it from the shell:
echo '' >> some.txt
In general, it's a good idea to ensure that text files end in a newline character in the first place, at least if they're intended to be used on UNIX-like systems.

parameter expansion using bang dollar (`!$`)

Is there any way to use !$ in a parameter expansion context? The desired usage that motivates this question is rapid (in terms of key strokes) alteration of the name of a file (e.g., instead of saving the file name in a variable and executing rsvg-convert $svg > ${svg/.svg/.png}, one could instead use rsvg-convert $! > $!{/.svg/.png}, where $!{/.svg/.png} is erroneous syntax intimating the desired effect; when the file in question was the last token on the preceding line, such a command can often be typed more quickly than alternatives like using tab completion in the presence of files sharing prefixes of varying length, or copying and pasting the file name by selecting with a mouse). As far as I can tell, there is no way to employ !$ in such a context, but perhaps through some chicanery a similar effect could be achieved.
Depending on how sophisticated you want the substitution, history expansion does support replacing the first occurrence of a string with another. You just precede the substitution with : like:
rsvg-convert !$ > !$:s/.svg/.png
You can see all the history modifiers here
At least in emacs-mode bash will also put the last argument of the previous command inline (not for expansion when you run the command) if you press alt+.. So in this case it might be fastest to type:
rsvg-convert
then alt+.>alt+. then delete the extension it just put in place with alt+bksp then the new extension: png
If you look further into the modifiers in Eric's example, you could also do:
rsvg-convert !$ > !$:r.png
Assuming .svg is a suffix of course

How to edit file content using zsh terminal?

I created an empty directory on zsh and added a file
called hello.rb by doing the following:
echo 'Hello, world.' >hello.rb
If I want to make changes in this file using the terminal
what's the proper way of doing it without opening the file
itself using let's say TextEditor?
I want to be able to make changes in the file hello.rb strictly
by using my zsh terminal, is this at all possible?
Zsh is not a terminal but a shell. The terminal is the window in which the shell executes. The shell is the text program prompting you commands and executing them.
If you want to edit the file within the terminal, then using vim, nano, emacs -nw or any other text-mode text editor will do it. They are not Zsh commands, but external commands that you can call from Zsh or from any other shell.
If you want to edit the file within Zsh, then use zed. You will need to run once (in ~/.zshrc)
autoload zed
and then you can edit hello.rb using:
zed hello.rb
(exit and save with Control-j)
You have already created and edited the file.
To edit it again, you can use the >> to append.
For example
echo "\nAnd you too!\n" >> hello.rb
This would edit the file by concatenating the additional string.
Edit, of course, by your use and definition of 'changing' a file, this is the simplest way to do so using the shell.
In a normal way, though you probably want to use a terminal editor.
Zed is a great answer, but to be even more stripped down - for a level of editing that even a script can do - zsh can hand all 256 characters/byte-values (including null) in variables. This means you can edit line by line or chunk by chunk almost any kind of file data directly from the command-line. This is approximately what zed/vared does. If you have a current version with all the standard modules included, it is a great benefit to have zsh/mapfile or zsh/system loaded so that you can capture any of the characters that are left out by command-expansion (zed uses $(<$file) to read a file to memory). Here is an example of a way you could use this variable manipulation method:
% typeset -T Buffer buffer $'\n'
% typeset -T Edit edit $'\n'
It is most common to use newline to divide a text file one wishes to edit.
This handy feature will make zsh give you full access to one line or a range of lines at a time without unintentionally messing with the data.
% zmodload zsh/mapfile
% Buffer=$mapfile[path/to/file]
Here, I use the handy mapfile module because I can load the contents of a file byte-for-byte. Alternately you can use % Buffer="$(<path/to/file)", like zed does, but you will always have the trailing newlines removed and other word splitting is possible with a typo or environment variation, so the simplicity of the module's method is best. When finished, you save the changes by simply assigning the $Buffer value back to the $mapfile[file] or use a more classic command like printf '%s' $Buffer >path/to/file (this is exact string writing, byte-for-byte, so any newlines or formatting you added back will be written).
You transfer the lines between Buffer and Edit using the mapped arrays as follows, however, remember that in its simplest form assigning one array to another drops elements that are completely empty (one \n \n two \n three becomes one \n two \n three). You can suppress this empty-element removal by quoting the input array and adding an '#' symbol to its index "$buffer[#]", if using the whole array; and adding the '#' symbol to the flags if using a range of the array "${(#)buffer[2,50]}". Preserving empty lines can be a bit troublesome for typing, but these multiple arrays should only be used in a script or function, since you can just edit one line at a time from the command line with buffer[54]="echo This is a newly written line."
% edit=($buffer[50,70])
...
% buffer[50,70]=($edit)
This is standard Zsh syntax, that means in the ... area you can edit and manipulate the $edit array of lines or the $Edit scalar block of text all you want, including adding more lines or taking some away. When you add the lines back into $buffer it will replace the specified block of lines (50-70) with the new lines, automatically expanding or reducing the other array elements to accommodate the reintegrated lines. -- Because of the dynamic array accommodations, you can also just insert whatever you need as a new line like this buffer[40]=("new string as new line" "$buffer[40]"). This inserts it before the index given, while swapping the order of the elements ("$buffer[40]" "new string as new line") inserts the new line after the index given. Either will adjust all following elements, including totally empty elements, to their current index plus one.
If you wanted to re-write the zed function to use this method in some complex way like: newzed /path/to/file [start-line] [end-line], that would be great and handy too.
Before I leave, I wanted to mention that using vared directly, once you have these commands typed on the interactive terminal, you may find it frustrating that you can't use "Enter" for inserting or appending new lines. I found that with my terminal and Zsh version using ESC-ENTER worked well, but I don't know about older versions (Mac usually comes stocked with a not-most-recent version, if my memory is right). If that doesn't work, you may have to do some documentation digging to learn how to set up your ZLE (Zsh Line Editor, a component of Zsh) or acquire a newer version of Zsh. Also, some other shells, when indexing a scalar variable may count by the byte because in ascii and C a byte is the same as a character, but Zsh supports UTF8 and will index a scalar string by the UTF8 character unless you turn off the shell option multibyte (on by default). This will help with manipulating each line if you need to use the old byte-character indexing. Also, if you have a version of Zsh that for whatever was not compiled with zsh/mapfile or zsh/system, then you can achieve a similar effect using number of options to the read builtin, like <path/to/file |read -u 0 -k $[5 * 2**20] -r -s Buffer ||(($#Buffer)). As you can see here, you have to make the read length big enough to accommodate the file's size or it will leave off part of the file, and the read return code will nearly always be an error because of not being able to read the full length of the string. We fix this with ||(($#Buffer)), but this builtin was simply not meant to handle large scale byte manipulation efficiently, so what you see is what you can get from it.

Sublime Text 2: Trim trailing white space on demand

I know that Sublime Text 2 can delete the trailing white space on files upon saving.
When working in a team and commiting a change to a file this tends to produce huge diffs which make peer code review more cumbersome. For that reason I prefer to only do the white space cleaning when I'm commiting huge changes to a file anyway and leave whitespace as it is for the minor changes.
I would like to know if there's any command for executing the trimming of the white space on demand on a file, other than "Activate trimming on save > Save file > Deactivate trimming".
Searching in the Documentation and on stackoverflow didn't show anything relevant, all the links seem to talk about the auto trimming on save.
I use these steps for a quick on-demand solution within Sublime Text:
Find > Replace...
Find What: [ \t]+\n
Replace With: \n
Replace All
You could also do this for a large set of files via
Find > Find in Files...
Find: [ \t]+\n
Where:
Replace: \n
Replace
Beware: using this plugin makes Sublime Text significantly slower
I use TrailingSpaces plugin for this.
Highlight trailing spaces and delete them in a flash.
ST2 provides a way to automatically delete trailing spaces upon file
save. Depending on your settings, it may be more handy to just
highlight them and/or delete them by hand. This plugin provides just
that!
Usage: click "Edit / Trailing Spaces / Delete".
To add a key binding, open "Preferences / Key Bindings - User" and add:
{ "keys": ["ctrl+alt+t"], "command": "delete_trailing_spaces" }
You can simply use a regex to remove trailing whitespaces:
Find > Replace...
Find what: [^\S\r\n]+$
Replace with: leave empty.
Click 'Replace All'
[^\S\r\n]+$ is Regex for "at least one whitespace character (so spaces and tabs but not newlines, using a double negation) followed by the end of the line"
Regular Expression must be enabled:
This method isn't perfect, but uses no plugins or settings and works in most situations.
Multi-Select and move cursor to the end of every line
Hold CTRL-Shift, Press Left, Right
The spaces and tabs at the end of the lines should now be selected. Press Delete or Backspace
Note - Special characters such as ( and + may also be selected at the end of the line at this point, not just spaces.
How to Multi-Select all lines:
One way is to use the middle mouse key to select vertically then hit the End Key if it's a small selection.
With hot-keys:
CTRL-A (select all)
CTRL-SHIFT-L (place cursor on all lines selected)
END (Go to end of lines)
You can also use the find function to find something that will be in every line, like the space character:
\s (using regex)
Click Find All
Press the "End" key to get multiple cursors at the end of each line
Sample Text:
text and number 44 more text and a space
text and number 44 more text and 2 tabs
text and number 44 more text and no space or tab
text and number 44 more text after a line feed
I found a soulution here:
http://www.sublimetext.com/forum/viewtopic.php?f=4&t=4958
You can modify the package
trim_trailing_white_space.py
located in the default packages directory, this way:
import sublime, sublime_plugin
def trim_trailing_white_space(view):
trailing_white_space = view.find_all("[\t ]+$")
trailing_white_space.reverse()
edit = view.begin_edit()
for r in trailing_white_space:
view.erase(edit, r)
view.end_edit(edit)
class TrimTrailingWhiteSpaceCommand(sublime_plugin.TextCommand):
def run(self, edit):
trim_trailing_white_space(self.view)
class TrimTrailingWhiteSpace(sublime_plugin.EventListener):
def on_pre_save(self, view):
if view.settings().get("trim_trailing_white_space_on_save") == True:
trim_trailing_white_space(view)
class EnsureNewlineAtEof(sublime_plugin.EventListener):
def on_pre_save(self, view):
if view.settings().get("ensure_newline_at_eof_on_save") == True:
if view.size() > 0 and view.substr(view.size() - 1) != '\n':
edit = view.begin_edit()
view.insert(edit, view.size(), "\n")
view.end_edit(edit)
Now you can add the command to your keymap configuration:
{ "keys": ["your_shortcut"], "command": "trim_trailing_white_space" }

How does one align code (braces, parens etc) in vi?

How do you prettify / align / format code in vi? What is the command?
I have pasted in a hunk of code and I need to have it all formatted/aligned... obviously I am a vi neophyte.
x
These commands in my answer work in vim. Most people who think they're using vi are using vim. To find out if your 'vi' is really 'vim', open vi and type :version -- if it's vim, it will say so. Otherwise you might just see a version number without the name of the program. Also, when you open vim for the first time you will usually see a splash screen of some sort that says "VIM - VI iMproved"...
Automatic Indentation
To turn auto-indentation on, make sure vim knows the file type you're editing (it usually automatically detects this from the file name extension, but might not figure it out with some file types). You can tell it the filetype using the menus for syntax highlighting. Then, do this:
:filetype indent on
You can disable auto-indentation with
:filetype indent off
Automatically adjusting/correcting indentation
In general, ={motion} will align code to an indentation level.
== align the current line
=i{ align the inner block
=% align to the matching parenthesis/bracket under the cursor
=14j or 14== align the next 14 lines
=G align to the end of the file
vG= same thing, align to the end of the
file (but using visual mode)
vjjj= align four lines (using visual mode)
Manual indentation
If vim is not guessing the indentation level correctly, there are two ways to change it:
If you are in normal mode (where everything is a command), do << to shift a line left, or >> to shift it right by one tab. You can do this with several lines by using the same movement commands I showed above (eg, >i{ indents the current inner code block).
If you are in insert mode, you can indent the line further (without moving the cursor) by doing a Ctrl-T, or un-indent one tab with Ctrl-D
Aligning equals signs, etc
If you want to align equals signs in a list of declarations, you should consider using this vim script: http://www.vim.org/scripts/script.php?script_id=294
Adjusting indentation/tab sizes
If you want vim to use spaces instead of tabs when it indents, run this command (or consider adding it to your vimrc file)
:set expandtab
To set how many spaces equal a tab, I usually do this:
:set expandtab softtabstop=3 tabstop=3 shiftwidth=3
tabstop - how many columns a tab counts for (affects display of existing tab characters)
shiftwidth - controls reindentation size with << and >>, among other commands.
softtabstop - how much space to insert when you press the tab key
expandtab - expand tab keys to spaces
But if you have to work with different amounts of tabs a lot, you could also use this function and keybinding:
function! Ktabs(tabsize)
execute "set softtabstop=" . a:tabsize . " tabstop=" . a:tabsize . " expandtab shiftwidth=" . a:tabsize
"set softtabstop=a:tabsize tabstop=a:tabsize expandtab shiftwidth=a:tabsize
endfunction
noremap <leader><Tab> :call Ktabs(3)<Left>
If you are editing a file with a mix of tabs and spaces, you may want to use this command after setting tab size:
:retab
={motion}
:h =
P.S. You shouldn't use vi if vim is available.
If manually adjusting indents I will open a visual block with V on the first or last line I want to re-indent, move to the brace containing the block, goto the other brace with % then shift the line with > or <
If indents are off by a lot I will shift everything all the way left with < and repeat it with . and then re-indent everything.
Another solution is to use the unix fmt command as described in Your problem with Vim is that you don't grok vi., {!}fmt

Resources