6

I am writing some documentation (a user guide), in markdown in Vim.

I now realise what I though should be one page, really should be 2. But I've already written alot of of both halves

How can I split the file at the cursor (or some other marker), into two separate files?

For Example:

Wholefile.md:

But I must explain to you how all this mistaken idea of denouncing of a pleasure and 
praising pain was born and I will give you a complete account of the system, and expound 
the actual teachings of the great explorer of the truth, the master-builder of human 
happiness.     
No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but 
because those who do not know how to pursue pleasure rationally encounter consequences 
that are extremely painful. Nor again is there anyone who loves or pursues or desires 
to obtain pain of itself, because it is pain, but occasionally circumstances occur in 
which toil and pain can procure him some great pleasure.

Part1.md:

But I must explain to you how all this mistaken idea of denouncing of a pleasure and 
praising pain was born and I will give you a complete account of the system, and expound 
the actual teachings of the great explorer of the truth, the master-builder of human 
happiness. 

Part2.md:

No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but 
because those who do not know how to pursue pleasure rationally encounter consequences 
that are extremely painful. Nor again is there anyone who loves or pursues or desires 
to obtain pain of itself, because it is pain, but occasionally circumstances occur in 
which toil and pain can procure him some great pleasure.
14
  1. Move the cursor to the last line of Part 1.

  2. Type Vgg to select the first part, and :w Part1.md<cr> to save that section to the first file.

  3. Press `>j, which will move the cursor to the first line of Part 2.

  4. Type VG to select the second part, and :w Part2.md<cr> to save that section to the second file.

  • 1
    by <cr> do you mean "Press the enter key"? – Lyndon White Feb 6 '15 at 1:47
  • 1
    @Oxinabox Yep. (That's just Vim's notation for a carriage return.) – Doorknob Feb 6 '15 at 1:47
  • 1
    Which i would need to use if I was making a macro, Ok cool. – Lyndon White Feb 6 '15 at 1:48
  • What happens to Wholefile.md. It still exists, right? – aharris88 Feb 6 '15 at 2:14
  • @aharris88 yes, no modifications are made to Wholefile.md due to these commands. – muru Feb 6 '15 at 2:20
3

Use line ranges with the :w command.

vim provides simple abbreviations in such ranges for places like first line 1, current line ., and last line $. Ranges can also accept calculated values, so e.g. $-5 is the fifth line from end of file. Using these abbreviations can make your task much easier:

Go the the first line that should be in the second file, then write everything above that line to Part1.md

:1,-1 w! Part1.md

and write everything on and after that line to Part2.md

:.,$ w! Part2.md

For more information on line ranges see :help range

1

I wrote this script sometime ago for a similar use case.

function! functions#Extract(bang,cmd,fname) range abort
  let extn = expand('%:e')
  if empty(extn)
    let l:fname = a:fname
  else
    let l:fname = a:fname . '.' . extn
  endif
  let [first, last] = [a:firstline, a:lastline]
  let range = first.",".last
  let spaces = matchstr(getline(first),"^ *")
  let buf = @@
  silent exe range."yank"
  let partial = @@
  let @@ = buf
  let old_ai = &ai
  try
    let &ai = 0
    silent exe "norm! :".range."change\<CR>".spaces.a:fname."\<CR>.\<CR>"
  finally
    let &ai = old_ai
  endtry
  execute a:cmd . ' ' . expand('%:p:h') . '/' . l:fname
  let @@ = partial
  silent put
  0delete
  let @@ = buf
  if !empty(spaces)
    silent! exe '%substitute/^' . spaces . '//'
  endif
endfunction

command! -bar -nargs=1 -range SExtract :<line1>,<line2>call functions#Extract(<bang>0,"split",<q-args>)
command! -bar -nargs=1 -range VExtract :<line1>,<line2>call functions#Extract(<bang>0,"vsplit",<q-args>)

What it essentially does is pretty much what you described. You can select a region of the current document in visual mode and invoke either SExtract or VExtract with a 'name' to open a new file with that name and the extension of the current file in either a split or vsplit. Then you can just save the other one.

This leaves the name of the new file in place of the content you extracted in the previous file. Which you could just remove I suppose or tweak this script accordingly.

NOTE: I made this long ago, and it was inspired by the code of Rextract that tpope provided in vim-rails plugin. I am sure it can be improved in several ways.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.