how to search for line without leading character in vim - linux

I have a config file of 500+ lines, however, there are only <10 lines uncommented, all teh other lines are commented.
The config file must maintain its integrity, only needed lines should be uncommented, so my question is:
In vim, how do I search for ALL lines with NO leading "#".
Sample portion of the config is like below:
#------------------------------------------------------------------------------
# Application(SingletonConfigurable) configuration
#------------------------------------------------------------------------------
## This is an application.
## The date format used by logging formatters for %(asctime)s
#c.Application.log_datefmt = '%Y-%m-%d %H:%M:%S'
## The Logging format template
#c.Application.log_format = '[%(name)s]%(highlevel)s %(message)s'
## Set the log level by value or name.
#c.Application.log_level = 30
Thank you.

If all the comments start with # in the first column, and you're only interested in non-empty lines, you can search for
/^[^#]
The ^ anchors the search at the start of each line, [^#] is a collection (:help /collection) that is negated (via the ^ - same character, different meaning!) to include any character but the #.
To include empty lines, append \|^$. To also accept whitespace in empty lines, \|^\s*$ instead.
Use folding instead of searching
If this is a large file, but you're actually only interested in tiny parts of it, Vim's built-in folding can remove all that commented clutter.
You can define a custom :help fold-expr that folds all those lines (getline()) that do not match (!~) the above regular expression (now enclosed in '...' because we need a String expression):
setlocal foldmethod=expr foldexpr=getline(v:lnum)!~'^[^#]'
Your buffer will then look like this:
+-- 10 lines: ------------------------------------------------------------------------------
c.Application.log_format = '[%(name)s]%(highlevel)s %(message)s'
+-- 3 lines: # Set the log level by value or name.
foo.bar = 1
You can open and close folds with commands like :help zo.

Related

Vim foldexpr matching pattern1 OR pattern2?

I want vim to create folds for my markdown files based on the header lines such
that for all lines below a particular header will be folded. E.g:
# Header
some lines of
text here
## Sub-header
some more lines of
text here # and a comment for some reason
# and an indented comment for good measure
# Another header
A new set of lines with a blank line(!)
for this header
## Another sub-header
yet more text
Should be folded like so:
# Header
+-- 2 lines: - some lines of -------------------
## Sub-header
+-- 3 lines: - some more lines of --------------
# Another header
+-- 3 lines: - A new set of lines --------------
## Another sub-header
yet more text
(I don't know what happens for a fold on a single line, so I'm happy with
whatever vim's default is - i.e. if vim doesn't do folds for single lines,
that's fine by me)
I've tried coming up with different regular expressions for this... I can match
all non-header lines except for blank lines:
autocmd FileType markdown setlocal foldexpr=getline(v:lnum)=~'^[^#]'
So I tried adding a second pattern to capture
blank lines with variation of ^[^#]\|^\s*$ (which does match everything but
non-header lines when I use it in a simple search with /) but then no folds
are produced and I don't know why (I tried different amounts of escape slashes
but to no avail):
" none of these work
autocmd FileType markdown setlocal foldexpr=getline(v:lnum)=~'^[^#]\|^\s*$'
autocmd FileType markdown setlocal foldexpr=getline(v:lnum)=~'^[^#]\\|^\\s*$'
You were almost there...you need 3 backslashes:
foldexpr=getline(v:lnum)=~'^[^#]\\\|^\\s*$'
Your regex string needs to end up having both a backslash and a vertical bar. Both of these characters need to be escaped in the expression. So you end up with \\ and \|...or 3 backslashes total.
source / additional reading
(side note: you could also switch to "very magic" mode with \\v, which would result in '\\v^[^#]\|^\\s*$'. If you had multiple "very magic" characters (e.g. |(){}+) this would be super helpful...but with a single vertical bar the only thing it might do is help with readability.)

Visual select and break multiple lines in VIM up to textwidth

If I have a few long lines like so
# I am Quater. Read my words, and be my friend.
# Father commands me to record the truth of history, so that readers will learn from those who went before.
# Therefore, I give each of my seven sons one of these self-engraving, history-recording klay walls.
I want to select the lines and issue a command and have it wrap to the text width while preserving the comment symbol (hashtag) to get the following
# I am Quater. Read my words, and be my friend.
# Father commands me to record the truth of
# history, so that readers will learn from
# those who went before. Therefore, I give each
# of my seven sons one of these self-engraving,
# history-recording klay walls.
I know there is a way to do this because I have done it before in VIM but I erased my .vimrc file and I can't find the solution anywhere on google
You can have Vim format the lines using the gq command. Either select the lines visually then use gq, or use gq followed by a motion (such as gq} to format until the next line), or use gqq with a count (3gqq to format the current line and the two that follow it).
For Vim to preserve comments, it needs two options to be set correctly. One is 'formatoptions', which needs to include q (to preserve comments over a gq operation), and the 'comments' option, which needs to include b:# to indicate that lines starting with a # are comments.
You can set both for the current buffer using:
setl fo+=q com+=b:#
After those settings, using gq will keep the comment characters at the start of lines when auto-formatting a block of comments.

Collect markdown headlines in vim?

I am trying to come up with a TOC (table of contents) of a text document:
lines starting with # (hashtag) VIM would "collect" into the buffer or maybe place them at the TOP OF FILE.
(Or - other idea - erase all lines in a duplicate file NOT starting with a #)
There must be solutions to this question...
I think you are looking for the :global command.
You can see all lines starting with # with :g/^#/p
and put them in a file using the :redir command :
:redir > toc.txt
:g/^#/p
:redir END
Note that toc.txt will contain the line numbers if you have set number. There is also this post on the subject.
Alternatively, you can delete all lines not starting with # with :v or :g! and save it to another file.
:v/\#/d
:w! toc.txt | undo
Look also for :copy (:t) and :move.
:global applies the command you provide to each matched lines in the order they appear in the file, so :g/^#/t0 will copy headers to the top of the file but in reverse. We could do :v/^#/m$ to move all non-header lines to the end, leaving the headers on top but stripped from the original text. Another way is to place some marker to mark the end of the table of content and copy header lines one line above this marker :
:g/^#/t?end-toc?-1

Change wrap width in a text file using Vim

I want to format srt subtitle text files to avoid wrapping problems on my media player.
I need to set a line wrap width to a number of characters e.g. 43
I can do this with Editplus, its a built in function and works well. The reason I want to do it in Vim, firstly Editplus is only available on the PC and the secondly Vim is badass.
I have found the following solution on the net..
:set tw=43
gggqG
It does work, but not exactly how I want it.
E.g.
I have this text:
557
00:47:39,487 --> 00:47:42,453
I will have to complete some procedures,
and I asked you to check out what they are for me
after I format it, I get:
557 00:47:39,487 --> 00:47:42,453 I will
have to complete some procedures, and I
asked you to check out what they are for
me
It seems to ignore line breaks/CRs. As you can see the "I will" has been added to the first line.
How do I get it to not ignore line breaks?
EDIT: apoligies about the formatting, first time using stackoverflow!
You could use the whitespace option of formatoptions and make the lines you want to wrap end in whitespace.
:set tw=43
:set fo+=w
:g/^\a/s/$/ /
gggqG
The third line adds a space on the end of any line starting with a letter and fo+=w stops gq from joining lines that don't end in spaces.
See:
:help fo-table
:help 'formatoptions'
:help gq
:help :g
Edit in response to comments
:g/^\a/s/$/ /
This translates to:
:g/ " Search the file
^\a " For lines starting (^) with an alphabetic character (\a - equivalent to [A-Za-z])
/ " Then on each line that the regexp matches (i.e. each line starting with an alphabetic character)
s/ " Substitute...
$ " The end of line (zero-width match at the end of the line)
/ / " With a space (slashes are delimiters)
The global (:g) command will only operate on the current file, but the textwidth and formatoptions lines will last for the whole session. If you want those options to only be used on the current buffer, use :setlocal instead:
:setlocal tw=43
:setlocal fo+=w
:help :setlocal
If the only lines you want to wrap are the ones that start with text (ignore the ones that start with numbers) you can use the following.
:g/^[a-zA-Z]/normal gqq
This will run p00ya's command on each text line in the file.
With the following text (i.e. only 3 lines):
557
00:47:39,487 --> 00:47:42,453
I will have to complete some procedures, and I asked you to check out what they are for me
Use gqq (format current line) on the 3rd line after setting tw. Formatting by paragraph will not work since vim will treat all 3 lines as part of the same paragraph (paragraphs only end with a blank line).
While not exactly robust (or elegant), if you can assume that the subtitle lines do not begin with numbers, you can configure Vim to treat them as comments.
:set comments=:0,:1,:2,:3,:4,:5,:6,:7,:8,:9
gggqG
Lines starting with 0-9 will be treated as comments and won't be merged together with the text.
I can't see exactly what the issue is due to the formatting of your post, but you might want to checkout the 'formatoptions' setting in vim's help, specifically :he fo-table which contains a bunch of customization flags.
This link might be useful.

How can I use Vim syntax files to collapse single line comments into one region?

I'm putting together a syntax for editing Java Manifest files (at github, if anyone's interested). I'm trying to collapse multiple single-line-comments (which I'm matching at the moment with syntax match manifestComment "#.*"). However, if I try to use a syntax region, then the entire file is marked and the entire thing collapses.
What I'm trying to achieve is this:
# A comment
# Another comment
# A third comment
Manifest-Version: 1
and have it collapse down into:
+-- 3 lines: # A comment ----
Manifest-Version: 1
The problem is that there's no distinct 'end' character, and the fold syntax doesn't help; so I can't do syntax region commentBlock start="^#" end="^[^#]". Roughly, the syntax region should start from the first hash character, and then continue down the lines until it finds a line which doesn't begin with a hash.
:set foldmethod=expr
:set foldexpr=getline(v:lnum)[0]==\"#\"
For information, :h fold-expr.
How about syntax region commentBlock start="^#" end="^#\#!"?
The \#! is like (?!pattern) in Perl, i.e. it matches with zero-width if the preceding atom -- # in this case -- does not match at the current position.

Resources