1" Vim Plugin:	Edit the file with an existing Vim if possible
2" Maintainer:	Bram Moolenaar
3" Last Change:	2016 Mar 28
4
5" To use add ":packadd! editexisting" in your vimrc file.
6
7" This plugin serves two purposes:
8" 1. On startup, if we were invoked with one file name argument and the file
9"    is not modified then try to find another Vim instance that is editing
10"    this file.  If there is one then bring it to the foreground and exit.
11" 2. When a file is edited and a swap file exists for it, try finding that
12"    other Vim and bring it to the foreground.  Requires Vim 7, because it
13"    uses the SwapExists autocommand event.
14
15" Function that finds the Vim instance that is editing "filename" and brings
16" it to the foreground.
17func s:EditElsewhere(filename)
18  let fname_esc = substitute(a:filename, "'", "''", "g")
19
20  let servers = serverlist()
21  while servers != ''
22    " Get next server name in "servername"; remove it from "servers".
23    let i = match(servers, "\n")
24    if i == -1
25      let servername = servers
26      let servers = ''
27    else
28      let servername = strpart(servers, 0, i)
29      let servers = strpart(servers, i + 1)
30    endif
31
32    " Skip ourselves.
33    if servername ==? v:servername
34      continue
35    endif
36
37    " Check if this server is editing our file.
38    if remote_expr(servername, "bufloaded('" . fname_esc . "')")
39      " Yes, bring it to the foreground.
40      if has("win32")
41	call remote_foreground(servername)
42      endif
43      call remote_expr(servername, "foreground()")
44
45      if remote_expr(servername, "exists('*EditExisting')")
46	" Make sure the file is visible in a window (not hidden).
47	" If v:swapcommand exists and is set, send it to the server.
48	if exists("v:swapcommand")
49	  let c = substitute(v:swapcommand, "'", "''", "g")
50	  call remote_expr(servername, "EditExisting('" . fname_esc . "', '" . c . "')")
51	else
52	  call remote_expr(servername, "EditExisting('" . fname_esc . "', '')")
53	endif
54      endif
55
56      if !(has('vim_starting') && has('gui_running') && has('gui_win32'))
57	" Tell the user what is happening.  Not when the GUI is starting
58	" though, it would result in a message box.
59	echomsg "File is being edited by " . servername
60	sleep 2
61      endif
62      return 'q'
63    endif
64  endwhile
65  return ''
66endfunc
67
68" When the plugin is loaded and there is one file name argument: Find another
69" Vim server that is editing this file right now.
70if argc() == 1 && !&modified
71  if s:EditElsewhere(expand("%:p")) == 'q'
72    quit
73  endif
74endif
75
76" Setup for handling the situation that an existing swap file is found.
77try
78  au! SwapExists * let v:swapchoice = s:EditElsewhere(expand("<afile>:p"))
79catch
80  " Without SwapExists we don't do anything for ":edit" commands
81endtry
82
83" Function used on the server to make the file visible and possibly execute a
84" command.
85func! EditExisting(fname, command)
86  " Get the window number of the file in the current tab page.
87  let winnr = bufwinnr(a:fname)
88  if winnr <= 0
89    " Not found, look in other tab pages.
90    let bufnr = bufnr(a:fname)
91    for i in range(tabpagenr('$'))
92      if index(tabpagebuflist(i + 1), bufnr) >= 0
93	" Make this tab page the current one and find the window number.
94	exe 'tabnext ' . (i + 1)
95	let winnr = bufwinnr(a:fname)
96	break
97      endif
98    endfor
99  endif
100
101  if winnr > 0
102    exe winnr . "wincmd w"
103  elseif exists('*fnameescape')
104    exe "split " . fnameescape(a:fname)
105  else
106    exe "split " . escape(a:fname, " \t\n*?[{`$\\%#'\"|!<")
107  endif
108
109  if a:command != ''
110    exe "normal! " . a:command
111  endif
112
113  redraw
114endfunc
115