Vim foldexpr matching pattern1 OR pattern2? - vim

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.)

Related

Redefine word movement stop characters for editing Clojure code in Vim/GVim

When editing Clojure code in Vim/GVim, I frequently use the w word-motion command (and its cousin b for backwards word-motion). However, in the default Clojure configuration Vim/GVim ignores common word separator chars such as hyphen, slash, and period. The following Clojure symbol shows all three:
clojure.core/select-keys
In this case, we want the w and b word-motion commands to stop at any of the non-alphabetic characters.
How can I modify the default Vim configuration to recognize these word boundaries in Clojure?
The answer is to use the Vim feature autocmd to modify the iskeyword setting for Clojure files. Specifically, add these lines to your ~/.vimrc file:
" Remove the period `.`, hyphen, `-`, and slash `/` as keyword chars so "word" movement will stop
" on these chars (i.e. in a namespace like `proj.some.long.ns.name` or a symbol like `my-clojure-sym`)
" Must do one at a time for 'string lists'
autocmd BufWinEnter,BufNewFile,BufRead *.clj* set iskeyword-=.
autocmd BufWinEnter,BufNewFile,BufRead *.clj* set iskeyword-=-
autocmd BufWinEnter,BufNewFile,BufRead *.clj* set iskeyword-=/
When loading a file with the suffix .clj*, we remove the three characters period, hypthen, and slash from the iskeyword string list, so they are no longer recognized as part of a "keyword". That is, they become word-separator characters. Then, the w and b word-motion commands will stop there, as we were seeking.
I add an answer for ideavim users since, this is the first google result.
Add this line to your .ideavimrc file:
set iskeyword=#,48-57,_,192-255,?,-,*,!,+,/,=,<,>,.,:,$

how to search for line without leading character in vim

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.

#vim: set only sort of working

I have .zsh-theme files (from oh-my-zsh), but they are not syntax highlighted. I was able to get this done pretty easily with
autocmd BufEnter *.zsh-theme set filetype=sh
However, before I did that I tried adding a vim meta comment for a specific file
#vim: set filetype=sh
The addition of the # apparently makes vim detect the file as a conf file, but it seems that this command is ignored (i.e. it is not detected as a sh file in spite of the comment). Is there any reason this may be happening?
Get rid of the word set (and add a space after the comment symbol)
# vim: filetype=sh
This fits with the first form of modelines
There are two forms of modelines. The first form:
[text]{white}{vi:|vim:|ex:}[white]{options}
[text] any text or empty
{white} at least one blank character (<Space> or <Tab>)
{vi:|vim:|ex:} the string "vi:", "vim:" or "ex:"
[white] optional white space
{options} a list of option settings, separated with white space
or ':', where each part between ':' is the argument
for a ":set" command (can be empty)
The syntax for this type of modeline is:
[text]{white}{vi:|vim:|ex:}[white]se[t] {options}:[text]
That is, try adding a space before vim:, and a trailing colon:
# vim: set filetype=sh:
You can find everything about modelines in
:h modeline
:h 'modeline'

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