Heading

This is some text inside of a div block.
This is some text inside of a div block.
This is some text inside of a div block.
min read

Goto Empty or Incomplete Paragraphs

Word • Macros • Editing
Peter Ronhovde
15
min read

More targeted navigation in your manuscripts reduces clicking around with the mouse making both writing and editing easier and faster.

One of the little tools toward that goal is jumping to an empty paragraph. I created it on a whim one day, but now I use it (actually its big brother) often when writing.

Thanks for your interest

This content is part of a paid plan.

Create the empty macro

A previous post covers creating an empty macro like the one shown below. When you’re done, you’ll have something like:

Sub GotoNextEmptyParagraph()
  ' Jump to the next empty paragraph in the document

End Sub

We'll need one for the next and another for the previous empty paragraph in the document.

The single quote tells VBA the rest of the text on that line is a comment meant for human readers. We start our macro steps on the empty line.

What about the “goto last edit” shortcut?

Yeah, that technically exists as Shift+F5 (cycle between last several edits), but it often counts individual characters as distinct “edits.”

While I find the idea intriguing, in practice Word’s implementation is only useful in isolated circumstances.

Basically, you can’t have made any significant changes, as in typing a single word, before trying to jump back to the previous edit location.

We can’t emulate this kind of behavior at the macro level (macros only know the state of the document while they are running), but we can create some targeted improvements to help us navigate our documents faster.

How can we jump to an empty paragraph?

This use case usually pops up for me when I’m working in a novel, and I move somewhere else to add a quick inline note. (Am I the only one that can’t stop myself from editing or adding notes as I write?)

Example of jumping to the next empty paragraph

This macro (or its big brother in the extended content below) is one of those that helps me quickly jump back to where I was working.

So how do we find the next empty paragraph?

Using Find (a simple introduction)

We need the Find method of the Selection (actually any Range object can use Find also).

There are a lot of parameters corresponding to all the options you see in the regular or advanced Find dialogs, but we’ll keep mostly to the simpler search options for now.

We access the Selection's Find method like so:

  Selection.Find

We do the actual find operation by telling it to “Execute”

  Selection.Find.Execute

What are we searching for?

We can set the search text using the FindText property.

  Selection.Find.Execute FindText:="Search text"

Don’t forget we use := to assign arguments when necessary in VBA commands.

Most text is included in double quotes when you give them as arguments in VBA, but there are exceptions for some special characters. This happens to be our case in this macro.

How to find an empty paragraph?

Think about what marks an empty paragraph …

Specifically, we’ll look for two paragraph markers side by side.

On paper, we just skip to the next line and start writing, but a paragraph marker is a special character in Word. We can’t literally put it inside double quotes, so we have to use the Word constant vbCr which indicates a Visual Basic (the “vb” part of the name) constant for a carriage return.

Searching for two of them together would look like:

  Selection.Find.Execute FindText:=vbCr + vbCr

We just “add” (called concatenate) the characters together to search for two side by side in the document.

Collapsing the selection

If you recall, when we Execute a Find operation in Word using the regular dialogs, Word automatically selects the text when it is found.

In our use case today, we’re just positioning the insertion point at the empty paragraph, so we don’t want the empty paragraphs selected when the macro is done.

So in our macro, we need to collapse the Selection after the search.

  Selection.Collapse

Repositioning the cursor

Unfortunately, collapsing the Selection like this will leave us at the end of the previous paragraph relative to the empty paragraph we found. After the collapse, we also need to move down a line.

  Selection.MoveDown

The default Unit for MoveDown is by line which is fine for us here.

If you remember our other macro examples, we can also collapse the Selection toward the End (using Direction:=wdCollapseEnd) instead of the beginning, but it doesn’t save any steps in this macro since the insertion point would finish on the next paragraph. We would then need to move up at this step instead.

What if it doesn’t find an empty paragraph?

Oh, we have to think about that?

Actually if it doesn’t find an empty paragraph, nothing happens with the find operation, but then we experience a side effect of the included included steps. The cursor would still move down one line.

Not really a problem, but it would look a little odd while you’re editing when you’re expecting to jump to an empty paragraph.

Was the search successful?

We really should have the macro only move down a line if an empty paragraph is found.

We can check for this using the Found property of Find.

  Selection.Find.Found

This property has a true value if your search text was found but false if nothing was found.

Conditional check on Find Found

Sounds perfect for a conditional If Then check. We’ve introduced it a few times before this, so I’ll jump right to how we use it.

  If Selection.Find.Found Then
    Selection.Collapse
    Selection.MoveDown
  End If

We now only collapse the selection and move down a line if the Find step actually finds the search text.

What about searching backward?

Of course, sometimes you’ll want to search backward in the document, and the Find method has a Forward parameter.

  Selection.Find.Execute FindText:=vbCr + vbCr, Forward:=False

It defaults to True (search forward in the document, of course), but you can set it to False to search backward.

Any gotchas?

Actually if you search backward in the text and then try to use the forward version, the Find method remembers the Forward setting to be False, so it’s safer to just give the direction explicitly for both macros.

In fact, it’s probably safer to give most of the related arguments for Find operations each time, but we’ll save that for the extended content below since it involves talking about some other stuff.

Final macros

The final versions of the macros are relatively simple with one for each direction with steps almost identical to each other.

Searching forward in the document:

Sub GotoNextEmptyParagraph()
  ' Jump to the next empty paragraph in the document
  Selection.Find.Execute FindText:=vbCr + vbCr, Forward:=True
  ' Move down to the empty paragraph if it was found
  If Selection.Find.Found Then
    Selection.Collapse
    Selection.MoveDown
  End If
End Sub

If you've come straight to the final macros, make sure you read above about why we specified Forward as True explicitly.

Searching backward in the document:

Sub GotoPreviousEmptyParagraph()
  ' Jump to the previous empty paragraph in the document
  Selection.Find.Execute FindText:=vbCr + vbCr, Forward:=False
  ' Move down to the empty paragraph if it was found
  If Selection.Find.Found Then
    Selection.Collapse
    Selection.MoveDown
  End If
End Sub

I assign these to keyboard shortcuts Command+Control+Space and Control+Option+Space, respectively, in Word for Mac.

While you might be skeptical of its use, in practice, I often ensure it’s utility by leaving an empty paragraph where I’m working, so I know I can always quickly jump back there almost immediately.

Personal variations

One of the cool things about macros is you can very much tailor them to your preferences, making Word work your way.

Here are some improvements I’ve made to my own variation of these macros.

Incomplete paragraphs

My personal version extends this idea to search for incomplete paragraphs (mostly those without ending punctuation). There are some caveats for styles like heading paragraphs, but I prefer this generalization of the idea.

A simplified version of this extension continues in the extended content below.

Excluding or targeting certain paragraph styles

A more thorough implementation might exclude certain paragraph styles like heading paragraphs which usually don’t have ending punctuation marks and would match the search text. (As I write, I usually insert many inline novel notes with specific paragraph styles which I want to skip when I’m working on the actual text.)

Alternatively, you might like to target certain paragraph styles, like Body Text in your novel, before committing to moving the insertion point.

There is an important gotcha to make it these restrictions work correctly since the obvious approach doesn’t work as expected in some cases.

Connected to this customization, I also have some logic to further detect whether I’m in a novel or a notes document and search differently in each case.

It’s a little more complicated than it may seem at first read, so I’ll share this stuff later in members’ content.

Limited search range

My version also limits the search range to a few pages since I tend not to like the idea of jumping to a random location in my novel where I forgot to finish the text line.

I suspect this behavior is a preference that is probably not shared by the majority of readers, so I won’t go through the details unless I get a lot of interest in it.

Improvements

I now introduce a simplified variant of my personal implementation of this macro concept.

How can we find an incomplete paragraph?

This may seem like a tall order. With the seemingly unlimited number of ways you can not finish a line, how do you detect any of them?

Setting more search parameters

We’ll need to specify more Find arguments to be safe which introduces the concept of With statements.

Essentially a With statement groups a set of related assignments or commands using the same object.

  With SomeObject.SomeMethod
    ' Insert related statements here ...
    ' Steps inside here are mostly part of SomeObject.SomeMethod
    ' where we use a . to reference them
    .SomeProperty = SomeValue
  End With

The .SomeProperty inside the With is equivalent to using

  SomeObject.SomeMethod.ExampleProperty

The With block just gives us a nice shorthand for repeated property or method references.

It’s technically ever so slightly faster, but in practice, you’d almost never notice the time difference.

The real advantages are just better organization and presentation of your steps and assignments, and you don’t have to repeat the SomeObject.SomeProperty reference over and over.

With blocks can include other commands, but generally it's probably better for your macro organization and clarity to limit any commands or assignments unrelated to the referenced object. It's your choice though.

Using With with Find

For today, we’re mostly setting search parameters for the Selection.Find method.

  With Selection.Find
    ' Setup search parameters
  .ClearFormatting
    .MatchWholeWord = False
    .MatchWildcards = True
    .MatchCase = False
    .Format = False
    .IgnoreSpace = False
    .MatchPhrase = False
    .Wrap = wdFindContinue
    .Forward = True

    ‘ Now do the search
    .Execute FindText:=SearchText
  End With

There’s a lot here, and I even left some options out for clarity. Several are intuitive doing what they say. I tend to include most of these just to be safe since Find remembers the previous search options like your regular Find dialog when you use it.

Each reference of a property must start with the . just as if you had typed it all together.

We don’t have time to talk about everything right now, but here are a few specific parameters relevant to today’s macro.

Most importantly, we need MatchWildCards to be True for our specific incomplete paragraph search.

One might think IgnoreSpace = True would be useful for finding incomplete paragraphs, but it is redundant with our fancier search argument below.

Indicating a target search style using .Style = “Some Style” doesn’t work in this macro for all cases since our search sometime spans an empty paragraph which may have a different paragraph style than the previous paragraph.

Finding incomplete paragraphs

Since we’ve set MatchWildCards, we can create a fancier search text. In fact, Word’s search text and search options are more robust than most people realize.

But the ending character could be anything?

How do we to reference any character?

For this macro, we want paragraphs that end with just letters, numbers, or a space but no punctuation marks.

Advanced search options

Typical, more commonly known, wildcards for searches include an asterisk “*” for any text after that point in the search string. “?” tells Word to allow any character for that specific character location in the search string. And more.

But we can get more specific than these allow alone. If you open the Word Advanced Find search dialog, you’ll see a whole list of more detailed search options.

We need a way to do this in VBA.

Finding any character

Specifically, we want any of several characters. For that, we use square brackets “[a-z]” in our search text string. This tells word to look for any of the characters in the range a-z which means any character of the English alphabet.

Since our search arguments above included MatchCase as False, the character range [a-z] also covers upper case English alphabet characters.

Now include numbers and a space to get a main part of the search string “[a-z0-9 ]”. (For any who find this notation familiar, it is similar to but not the same as search operations performed using RegEx.)

What’s not included are punctuation marks.

For clarity, the first character of the search text must include at least one of the characters in the brackets.

Including paragraph markers in the search text

Back in the GotoNextEmptyParagraph macro at the top, we searched for two paragraph markers using a search string vbCr + vbCr. That is, we set FindText to side by side paragraph markers as an indicator of an empty paragraph.

We still need the vbCr characters, but in this case the first one should be optional for incomplete paragraphs.

How do we combine this with the other optional characters above? We add the first one to the optional list and a second one after it like so:

  "[a-z0-9 " + vbCr + "]" + vbCr

Unfortunately, we need to add the first vbCr inside the square brackets to make it one of the optional set of first characters. This is why we have to add the right square bracket “]” after the first vbCr.

Then we add the second vbCr outside the brackets making it a required second character.

Paragraph marker side notes

There is another way to set the FindText search string using ^13 in place of vbCr for the paragraph marker:

  "[a-z0-9 ^13^13"

It’s not horrible. Just a little messier. On the other hand, everything is in one set of double quotes, so maybe you prefer this version. It’s actually what I use.

Technically, Microsoft also allows a “^p” to indicate a paragraph marker in the FindText search string, but it doesn’t quite work as expected here since it can’t be used with MatchWildcards set to True.

I don’t know why Microsoft restricted its use like this, but in this macro, we have to use wildcards to match incomplete paragraphs, so we’re stuck with using one of the other constants.

Executing the new search

Now our search command would look like:

  Selection.Find.Execute FindText:="[a-z0-9 " + vbCr + "]" + vbCr

This is a little long and messy, so we can improve the presentation using a variable.

  SearchText = "[a-z0-9 " + vbCr + "]" + vbCr
  Selection.Find.Execute FindText:=SearchText

In general, messy code is hard to read, so you can often help yourself when you come back to it later by cleaning it up a little now. Word and VBA don’t care though. Your tolerance for what you consider “messy” will improve with experience.

Reviewing the search text

Let’s break this search text down again just to be as clear as possible.

This first part of the search text in square brackets “[a-z0-9 ” + vbCr + “]” tells Word to look for any character consisting of an alphabetic character, number, space, or a paragraph marker as the single first character match of the search.

This first character is required for a valid match.

Then the ending vbCr requires the last character of the two characters of matched search text to be a paragraph marker meaning we are always searching for the end of a paragraph.

Revised macro finish

If you test the macro, and you should, you'll notice that the finishing steps of collapsing the Selection and moving down don't work correctly for an incomplete paragraph.

What changed?

For an incomplete paragraph, the original MoveDown command now moves to the first line of the next paragraph. Why?

There is no empty paragraph to move into now.

The fix is simple: Since we only have two characters in any found text here, instead of moving down a line after the collapse, we just have to move to the right one character.

  Selection.Collapse
  Selection.MoveRight  ' Solves both cases

The default Unit for a MoveRight is by character.

This works for either case. For an empty paragraph, we're moving past the first paragraph marker and into the next paragraph since a paragraph marker counts as a character. It just happens to also divide paragraphs (and store formatting information in Word).

For an incomplete paragraph, we're moving past first character which happens to be a letter, number, or a space.

Don't over complicate things

It's worth a teaching moment to take an aside here. Don't pull a Rube Goldberg solution out of a hat to fix simple problems.

Sometimes the macro does have to be complicated, but only do that when necessary.

In the finishing steps correction above, I originally corrected it with nested conditional statements like so:

  ' Check whether we found an incomplete or empty paragraph
  If Selection.Find.Found Then
    ' Check for type of paragraph found
    If Selection.Characters.First.Text = vbCr Then
      ' Found an empty paragraph so collapse Selection
      ' and move down
      Selection.Collapse
      Selection.MoveDown
    Else
      ' Found an incomplete paragraph so collapse Selection
      ' and move right past the first character
      Selection.Collapse
      Selection.MoveRight
    End If
  End If

This does solve the problem, but it was at the moment I added the MoveRight step near the bottom when I realized it would solve both problems which is a good marker of a better solution.

Final macros

The final versions of the macros are relatively simple with one for each direction with steps almost identical to each other.

Searching forward in the document:

Sub GotoNextEmptyParagraph()
  ' Jump to the next empty or incomplete paragraph in the document
  ‘ Define search text for an empty or incomplete paragraph ending
  SearchText = "[a-z0-9 " + vbCr + "]" + vbCr

  With Selection.Find
    ' Setup search parameters
    .ClearFormatting
    .MatchWholeWord = False
    .MatchWildcards = True
    .MatchCase = False
    .Format = False
    .IgnoreSpace = False
    .MatchPhrase = False
    .Wrap = wdFindContinue
    .Forward = True

    ‘ Now do the search
    .Execute FindText:=SearchText
  End With

  ‘ Position insertion point at end of found paragraph
  If Selection.Find.Found Then
    Selection.Collapse
    Selection.MoveRight
  End If
End Sub

Notice we put also the Execute inside the With block of commands.

Searching backward in the document:

Sub GotoPreviousEmptyParagraph()
  ' Jump to the previous empty or incomplete paragraph in the document
  ‘ Define search text for an empty or incomplete paragraph ending
  SearchText = "[a-z0-9 " + vbCr + "]" + vbCr

  With Selection.Find
    ' Setup search parameters
    .ClearFormatting
    .MatchWholeWord = False
    .MatchWildcards = True
    .MatchCase = False
    .Format = False
    .IgnoreSpace = False
    .MatchPhrase = False
    .Wrap = wdFindContinue
    .Forward = True

    ‘ Now do the search
    .Execute FindText:=SearchText
  End With

  ‘ Position insertion point at end of found paragraph
  If Selection.Find.Found Then
    Selection.Collapse
    Selection.MoveRight
  End If
End Sub

I assign these to keyboard shortcuts Command+Control+Space and Control+Option+Space, respectively, in Word for Mac.

Common steps comment

Notice all that changed from the Next to the Previous version was setting Forward to False to make it search backward in the document.

With all the common steps in these macros, it’s easy to see why programmers invented functions and subroutines, but that is a lesson for another day.

Affiliate Links

If you're interested in using Word or another tool related to the article, check out these affiliate links. I may make a small commission if you purchase when using them, but there is no increase in cost for you, and it helps to support this site and associated content.

I've been using Microsoft for Business for commercial use (that's us writers) on one of the lower pricing tiers for years. I get to use my macros, have online storage, and don't have to worry about software updates.