118

The standard J command for joining lines replaces the newline character(s) with a space. It's useful when editing 'literature' but can be troublesome if I, say, edit a hex dump by hand if I forget to remove the superfluous space.

Is there a quick & easy method to join two lines without producing a space between them?

200_success
  • 9,549
  • 5
  • 51
  • 64
SF.
  • 2,089
  • 4
  • 15
  • 14

5 Answers5

144

The gJ mapping does this; from :help gJ:

Join [count] lines, with a minimum of two lines. Don't insert or remove any spaces.

You could rebind it to J, if you want to save a keystroke:

:nnoremap J gJ

Note that this doesn't remove any spaces, so if either the current line ends with a space or next line starts with one or more spaces they will be left as is; so this:

Hello
    world

Becomes:

Hello    world

We could use Jx in this case, then it will be Helloworld, but that won't work in all cases; from the help:

Join the highlighted lines, with a minimum of two lines. Remove the indent and insert up to two spaces

[...]

These commands, except "gJ", insert one space in place of the unless there is trailing white space or the next line starts with a ')'.

So in some cases more than one space or no space is inserted. As far as I can see, there is no easy way to change this behaviour; I created a function to modify gJ to always join without spaces:

" Like gJ, but always remove spaces
fun! s:join_spaceless()
    execute 'normal! gJ'

    " Remove character under the cursor if it's whitespace.
    if matchstr(getline('.'), '\%' . col('.') . 'c.') =~ '\s'
        execute 'normal! dw'
    endif
endfun

" Map it to a key
nnoremap <Leader>J :call <SID>join_spaceless()<CR>

If you want, you can add let save = winsaveview() at the start of the function, and call winrestview(save) at the end to prevent the cursor from moving (but the current behaviour is the same as gJ).

See also: :help J, :help 'joinspaces'

Martin Tournoij
  • 62,054
  • 25
  • 192
  • 271
  • Is it possible to use some "Preserve" function to keep the cursor position when using this function or how do I get this result? – SergioAraujo Dec 15 '17 at 12:19
  • Very late reply @SergioAraujo, but yeah, you can use let save = winsavesave() at the start, and winrestview(save) at the end. – Martin Tournoij Apr 11 '20 at 11:33
  • normal! "_dw would prevent the deleted whitespace from stomping your @" register. Execute doesn't seem necessary for the two normal commands. Thanks for this answer! – idbrii Feb 15 '22 at 18:22
  • Unfortunately does not work from visual mode with multiple lines selected, only the last line join will have spaces removed :/ – bew May 09 '22 at 22:11
12

Another trick you may try is to use replace. Sometimes this might be useful.

%s/$\n//g

Scenario: Delete the last character and join with the next line:

%s/=$\n\(.\)/\1/g

For example,

xxxx=
123

becomes:

xxxx123
insidepower
  • 231
  • 2
  • 4
4

Create a macro and reuse it:

qaJxq

Now replay the macro, a by using @a wherever you want to join two lines with no space.

@@ will repeat the previous macro. So you can just hold @ to join multiple lines.

Martin Tournoij
  • 62,054
  • 25
  • 192
  • 271
pellucide
  • 141
  • 1
  • 1
    Why type @a when you can type Jx? Same number of key presses and SHIFT presses! – Shahbaz Jan 19 '17 at 01:37
  • 2
    @Shahbaz Maybe because of the last line: "you can just hold @" – muru Jan 19 '17 at 03:13
  • 1
    @muru, that's true! – Shahbaz Jan 19 '17 at 15:23
  • 8
    It also makes it a repeatable command, so you can use 3@a to join 3 lines, whereas doing 3Jx would join 3 lines with spaces and then delete the space between the second and third lines, leaving spaces between the other lines. – Haegin Feb 27 '17 at 18:05
4

To always join with a single space :

nmap J gJi <ESC>ciW <ESC>

To join with no space at all (removes trailing+leading space) :

nmap <C-J> gJi <ESC>diW
statox
  • 49,782
  • 19
  • 148
  • 225
phil
  • 41
  • 1
  • 1
    Welcome to this site! Your mappings look a bit over-engineered to me, it would be helpful if you could add a bit more explanations about how they work. – statox Apr 09 '19 at 15:31
  • gJ joins the lines, bringing leading whitespace with them: Hello| world (the cursor is after Hello) Then i <ESC> enters insert mode, inserts a space, then escapes back to normal mode. Then ciW <ESC> is the "change in word" command, followed by a space, which replaces all the whitespace after the cursor, then escapes back to normal mode. Hello world – Robert Carter Mills Feb 26 '23 at 00:37
2

Select the lines you'd like to merge, enter an Ex command by typing a colon : in normal mode. Then type this command:

s/$\n\s*//gc

The entire command should look likewise:

:'<,'>s/$\n\s*//gc

This is actually a tweaked version of the @insidepower's command that replaces space-indentations as well as newline characters.

Explanation:

  • '<,'> means that we modify only the lines selected in visual mode.

  • /$\n\s* is a regex pattern. We're looking for a match that ends $ with a new line character \n and has non-determined number of whitespaces * thereafter.

  • s/pattern//gc is a substitute command to find each pattern and replace it with an empty character on confirmation.

To figure out more about flags and metacharacters for regular expressions in Vim take a look at this chapter of Vim Reference.

aubique
  • 21
  • 2
  • 2
    Hi ubique, welcome to [vi.se]! You've got a pretty well-written answer there; kudos for that. My one nitpick is that vim regular expressions =/= python regular expressions, and sometimes that is confusing for users. Maybe link to the help document for Vim regex instead? – D. Ben Knoble Oct 08 '19 at 02:07
  • 2
    Second nit: the answer you reference was written by @insidepower and edited by Peter. – D. Ben Knoble Oct 08 '19 at 02:08
  • This solution is almost perfect! add :keeppatterns before to keep the search untouched. Also it joins 1 line too much compared to J in visual mode, apart from that it's great! – bew May 09 '22 at 21:19