606 lines
21 KiB
Plaintext
606 lines
21 KiB
Plaintext
*fswitch.txt* For Vim version 7.2 and above Last change: 2009 Mar 23
|
|
|
|
---------------
|
|
File Switcher
|
|
---------------
|
|
|
|
Author: Derek Wyatt (derek at myfirstnamemylastname dot org)
|
|
|
|
*fswitch-copyright*
|
|
Copyright: The VIM LICENSE applies to fswitch.vim, and fswitch.txt
|
|
(see |copyright|) except use "fswitch" instead of "Vim".
|
|
No warranty, express or implied.
|
|
Use At-Your-Own-Risk!
|
|
|
|
==============================================================================
|
|
*fswitch* *fswitch-contents*
|
|
1. Contents~
|
|
|
|
1. Contents .............................: |fswitch-contents|
|
|
2. About ................................: |fswitch-about|
|
|
3. Features .............................: |fswitch-features|
|
|
4. Setup ................................: |fswitch-setup|
|
|
5. Configuration ........................: |fswitch-configure|
|
|
6. "Creating" the Alternate File ........: |fswitch-altcreate|
|
|
7. Useful Mappings ......................: |fswitch-mappings|
|
|
8. FSwitch() ............................: |fswitch-function|
|
|
9. FSReturnCompanionFilenameString().....: |fswitch-getcompanion|
|
|
10. FSReturnReadableCompanionFilename()...: |fswitch-getreadablecomp|
|
|
11. The Default Settings .................: |fswitch-defaults|
|
|
12. Examples .............................: |fswitch-examples|
|
|
13. Troubleshooting ......................: |fswitch-trouble|
|
|
A. Change History .......................: |fswitch-changes|
|
|
|
|
==============================================================================
|
|
*fswitch-about*
|
|
2. About~
|
|
|
|
FSwitch is designed to allow you to switch between companion files of source
|
|
code (e.g. "cpp" files and their corresponding "h" files). The source for
|
|
this came from a home-grown script that was influenced later by the
|
|
"Alternate" (a.vim) script.
|
|
|
|
The original intention was to modify the existing a.vim script to do what the
|
|
home-grown version could do (choose to open the other file in an existing
|
|
window) but it was a rather complex script and modification looked difficult
|
|
so the choice was made to simply move the home-grown script forward a couple
|
|
of notches and produce a new plugin. This doc file is twice the length of the
|
|
actual code at this point :)
|
|
|
|
==============================================================================
|
|
*fswitch-features*
|
|
3. Features~
|
|
|
|
FSwitch has the following features:
|
|
|
|
- Switches between a file and its companion file
|
|
- Ability to create a new file using a preferential location
|
|
- Simple configuration using buffer-local variables
|
|
- It's got a really long doc file (... seriously, why is this thing so
|
|
bloody long?)
|
|
- Umm... other stuff?
|
|
|
|
==============================================================================
|
|
*fswitch-setup*
|
|
4. Setup~
|
|
|
|
Most of the behaviour of FSwitch is customized via buffer-local variables.
|
|
You set up the variables with auto commands:
|
|
>
|
|
au! BufEnter *.cpp let b:fswitchdst = 'hpp,h' | let b:fswitchlocs = '../inc'
|
|
<
|
|
That |:autocmd| will set the 'fswitchdst' and 'fswitchlocs' variables when the
|
|
|BufEnter| event takes place on a file whose name matches {*.cpp} (e.g. when
|
|
you enter the buffer containing the {MyFile.cpp} file).
|
|
|
|
The variables above state that the alternate file to {MyFile.cpp} are
|
|
{MyFile.hpp} and {MyFile.h} preferred in that order, and located in the {inc}
|
|
directory at the same level as the current directory.
|
|
|
|
That should get you there but there's more capability here if you want. To
|
|
get that move on to |fswitch-configure|.
|
|
|
|
==============================================================================
|
|
*fswitch-configure*
|
|
5. Configuration~
|
|
|
|
|
|
*'fswitchdst'*
|
|
'fswitchdst' string (default depends on file in current buffer)
|
|
local to buffer
|
|
|
|
The 'fswitchdst' variable denotes the file extension that is the
|
|
target extension of the current file's companion file. For example:
|
|
>
|
|
:let b:fswitchdst = 'cpp,cxx,C'
|
|
<
|
|
The above specifies that the current buffer's file has a companion
|
|
filename which can be found by replacing the current extension with
|
|
{cpp}, {cxx} or {C}. The extensions will be tried in this order and
|
|
the first match wins.
|
|
|
|
'fswitchdst' is taken relative to directories that are found in the
|
|
'fswitchlocs' variable.
|
|
|
|
*'fswitchlocs'*
|
|
'fswitchlocs' string (default depends on file in current buffer)
|
|
local to buffer
|
|
|
|
The 'fswitchlocs' variable contains a set of directives that indicate
|
|
directory names that should be formulated when trying to find the
|
|
alternate file. For example:
|
|
>
|
|
" Create the destination path by substituting any
|
|
" 'include' string from the pathname with 'src'
|
|
:let b:fswitchlocs = 'reg:/include/src/'
|
|
|
|
" First try adding the relative path '../src' to the path
|
|
" in which the file in the buffer exists and if that fails
|
|
" then try using 'source' instead
|
|
:let b:fswitchlocs = 'rel:../src,source'
|
|
|
|
" Same as above but leaving off the optional 'rel:'
|
|
:let b:fswitchlocs = '../src,../source'
|
|
<
|
|
The following types of directives are understood:
|
|
|
|
*fswitch_reg*
|
|
reg:~
|
|
A regular expression. The regular expression takes the form:
|
|
>
|
|
{delim}{pat}{delim}{globsub}{delim}
|
|
<
|
|
Where:
|
|
|
|
{delim} is something that doesn't appear in {pat} or
|
|
{globsub} used to delimit the {pat} and {globsub}
|
|
|
|
{pat} is a standard pattern to search on
|
|
|
|
{globsub} is a substitution string that will be run through
|
|
the |glob()| function.
|
|
|
|
*fswitch_rel*
|
|
rel:~
|
|
A relative path. The {rel:} is actually optional. If you
|
|
leave this off, then FSwitch will assume that the string is
|
|
denoting a relative path.
|
|
|
|
*fswitch_ifrel*
|
|
ifrel:~
|
|
Takes the same form as {:reg} but the {globsub} part of the
|
|
directive is a relative path. The relative path is only used
|
|
if the {pat} matches the existing path of the buffer.
|
|
|
|
*fswitch_abs*
|
|
abs:~
|
|
An absolute path. I have no idea why you'd ever want to do
|
|
this, but it's there if you want it.
|
|
|
|
*fswitch_ifabs*
|
|
ifabs:~
|
|
Takes the same form as {:reg} but the {globsub} part of the
|
|
directive is an absolute path. The absolute path is only used
|
|
if the {pat} matches the existing path of the buffer.
|
|
|
|
Why use the "if" variants?
|
|
|
|
Here's the situation: You've got the following file:
|
|
>
|
|
~/code/MyFile.h
|
|
<
|
|
And you've set the following locations:
|
|
>
|
|
For .h -> reg:/include/src/,../src,./
|
|
For .cpp -> reg:/src/include/,../include,./
|
|
<
|
|
Here's what happens when run the following commands:
|
|
>
|
|
FSwitch('%')
|
|
# Creates a new file ~/src/MyFile.cpp due to the first
|
|
# relative path in the list for .h
|
|
FSwitch('%')
|
|
# Creates a new file ~/include/MyFile.h due to the first
|
|
# regular expression in the list for .cpp
|
|
<
|
|
The problem is that you've unconditionally said you want to use
|
|
{../src} for the alternate file but in reality you probably wanted to
|
|
use {./}. If you use {:ifrel} instead then you can say that you only
|
|
want to use {../src} if the path to the current buffer contains
|
|
{/include/} or something like that. If you did this FSwitch would not
|
|
have taken {../src} for the new file but would have chosen {./}
|
|
|
|
So the "right" setup is:
|
|
>
|
|
For .h -> reg:/include/src/,ifrel:|/include/|../src|,./
|
|
For .cpp -> reg:/src/include/,ifrel:|/src/|../include|,./
|
|
<
|
|
*'fswitchdisablegloc'*
|
|
'fsdisablegloc'
|
|
string (default off)
|
|
local to buffer
|
|
|
|
Disables the appending of the default global locations to the local
|
|
buffer definition. Normally when processing alternate file locations
|
|
FSwitch will append some default values to the list of locations. If
|
|
you define this variable then this will not happen.
|
|
|
|
The default locations are currently set to "./" or ".\" depending on
|
|
what slash your configuration evaluates to.
|
|
|
|
*'fswitchfnames'*
|
|
'fswitchfnames' string (default depends on file in current buffer)
|
|
local to buffer
|
|
|
|
The 'fswitchfnames' variable contains a comma-separated list
|
|
of possible substitution patterns over the base filename (without path
|
|
and extension) that should be formulated when trying to find the
|
|
alternate file. The format of the substitution pattern is the same
|
|
as |fswitch-reg|.
|
|
|
|
This may be useful when the companion file may can be formulated by
|
|
adding a suffix to the base filename. For instance, when the companion
|
|
of MyClass.java is MyClassTest.java.
|
|
|
|
For example:
|
|
>
|
|
" Create the destination filename by appending 'Test'
|
|
" to the filename
|
|
:let b:fswitchfnames = '/$/Test/'
|
|
|
|
" Create the destination filename by removing 'Test'
|
|
" from the end of the filename.
|
|
:let b:fswitchfnames = '/Test$//'
|
|
<
|
|
*'fswitchnonewfiles'*
|
|
'fsnonewfiles'
|
|
string (default off)
|
|
local to buffer and global
|
|
|
|
This variable is both global and local. If you want to disable the
|
|
creation of the alternate file when it doesn't already exist you can
|
|
choose to do this on a per-extension basis or globally. Set the
|
|
global one to shut it off all the time and use the buffer version to
|
|
shut it off locally.
|
|
|
|
*'fsneednomatch'*
|
|
'fsneednomatch'
|
|
string (default off)
|
|
local to buffer and global
|
|
|
|
Normally when doing a regular expression alteration of the path (see
|
|
{reg:} in 'fswitchdst' the pattern you're going to substitute the
|
|
value with must actually match in the string. When it doesn't matter
|
|
whether or not that the match actually takes place, you can set this
|
|
value.
|
|
|
|
If you do set this then the failure to match actually results in
|
|
nothing happening at all. So if the right filename exists in the same
|
|
directory as the one you're switching from then that's the one that
|
|
will be switched to.
|
|
|
|
Example:
|
|
>
|
|
|
|
If the b:fswitchlocs is set to
|
|
|
|
reg:/src/include/,include
|
|
|
|
and
|
|
|
|
# This is the file we're editing
|
|
~/code/program/myfile.c
|
|
|
|
# These choices exist for the header file
|
|
~/code/program/myfile.h
|
|
~/code/program/include/myfile.h
|
|
<
|
|
Then the first substitution will result in the first header file being
|
|
chosen, not the second.
|
|
|
|
==============================================================================
|
|
*fswitch-altcreate*
|
|
6. "Creating" the Alternate File~
|
|
|
|
If the file being switched to does not exist, and 'fsnonewfiles' has not been
|
|
set, then it will be created as a new, unwritten buffer. If there are
|
|
multiple possibilities here, FSwitch prefers the first possible match. For
|
|
example if the current buffer has a filename called {/code/src/a/b/MyFile.cpp}
|
|
and has the following set:
|
|
>
|
|
let b:fswitchdst = 'h,hpp'
|
|
let b:fswitchlocs = 'reg:/src/include/,../include,../inc'
|
|
<
|
|
then the created filename will be {/code/include/a/b/MyFile.cpp}.
|
|
|
|
As stated, this file hasn't actually been written to yet so you could easily
|
|
delete the buffer and there's no harm done but you also may not be able to
|
|
write the buffer very easily if the directory hierarchy doesn't yet exist. In
|
|
this case, it's quite helpful to define a mapping for easily creating the
|
|
directory for you:
|
|
>
|
|
nmap <Leader>md :!mkdir -p %:p:h<cr>
|
|
<
|
|
Then it's pretty easy to create the directory before writing the file.
|
|
|
|
==============================================================================
|
|
*fswitch-mappings*
|
|
7. Useful Mappings~
|
|
|
|
I didn't bother putting mappings into the script directly as this might have
|
|
caused conflicts and I don't know how to avoid those. I use the following
|
|
mappings myself:
|
|
|
|
- Switch to the file and load it into the current window >
|
|
nmap <silent> <Leader>of :FSHere<cr>
|
|
<
|
|
- Switch to the file and load it into the window on the right >
|
|
nmap <silent> <Leader>ol :FSRight<cr>
|
|
<
|
|
- Switch to the file and load it into a new window split on the right >
|
|
nmap <silent> <Leader>oL :FSSplitRight<cr>
|
|
<
|
|
- Switch to the file and load it into the window on the left >
|
|
nmap <silent> <Leader>oh :FSLeft<cr>
|
|
<
|
|
- Switch to the file and load it into a new window split on the left >
|
|
nmap <silent> <Leader>oH :FSSplitLeft<cr>
|
|
<
|
|
- Switch to the file and load it into the window above >
|
|
nmap <silent> <Leader>ok :FSAbove<cr>
|
|
<
|
|
- Switch to the file and load it into a new window split above >
|
|
nmap <silent> <Leader>oK :FSSplitAbove<cr>
|
|
<
|
|
- Switch to the file and load it into the window below >
|
|
nmap <silent> <Leader>oj :FSBelow<cr>
|
|
<
|
|
- Switch to the file and load it into a new window split below >
|
|
nmap <silent> <Leader>oJ :FSSplitBelow<cr>
|
|
<
|
|
==============================================================================
|
|
*FSwitch()*
|
|
8. FSwitch()~
|
|
|
|
The main work is done by the FSwitch() function. The reason it's documented
|
|
here is because you can use it to do something more interesting if you wish.
|
|
As it stands now, you get the "Split Above and Switch" functionality by
|
|
calling FSwitch() like this:
|
|
>
|
|
FSwitch('%', 'split \| wincmd k')
|
|
<
|
|
There's probably not much to stop anyone from doing something more interesting
|
|
in the second argument. If this string is non-empty then it will be run
|
|
through an |:execute| call.
|
|
|
|
==============================================================================
|
|
*fswitch-getcompanion* *FSReturnCompanionFilenameString()*
|
|
|
|
9. FSReturnCompanionFilenameString()~
|
|
|
|
This function is used by |FSwitch()| to return the pathname to the preferred
|
|
companion file. In this case, the file need not actually exist on the
|
|
filesystem but would be the one created if you chose to do so. As an
|
|
example:
|
|
>
|
|
let path = FSReturnCompanionFilenameString('%')
|
|
<
|
|
The resultant path string contains the preferred companion file or nothing if
|
|
no preferred file could be discovered.
|
|
|
|
==============================================================================
|
|
*fswitch-getreadablecomp* *FSReturnReadableCompanionFilename()*
|
|
|
|
10. FSReturnReadableCompanionFilename()~
|
|
|
|
This function returns the companion file, but the companion file must be
|
|
readable on the filesystem for it to be successfully returned.
|
|
>
|
|
let path = FSReturnReadableCompanionFilename('%')
|
|
<
|
|
The resultant path string contains the preferred companion file or nothing if
|
|
no preferred file could be found on the filesystem.
|
|
|
|
In order to see what created the need for this function, see
|
|
|fswitch-example3|.
|
|
|
|
==============================================================================
|
|
*fswitch-defaults*
|
|
11. The Default Settings~
|
|
|
|
By default FSwitch handles {c}, {cc}, {cpp}, {cxx} and {C}. Note that the
|
|
difference between {c} and {C} is only case sensitivity. This may mean that
|
|
weird stuff happens if your OS is case insensitive.
|
|
|
|
Also NOTE that when you use {cxx/hxx} or {C/H}, god kills a puppy.
|
|
Consider that next time you want to do such a silly thing.
|
|
|
|
For *.h files:
|
|
>
|
|
let b:fswitchdst = 'c,cpp'
|
|
let b:fswitchlocs = 'reg:/include/src/,reg:/include.*/src/,../src'
|
|
<
|
|
|
|
For *.hpp files:
|
|
>
|
|
let b:fswitchdst = 'cpp'
|
|
let b:fswitchlocs = 'reg:/include/src/,reg:/include.*/src/,../src'
|
|
<
|
|
|
|
For *.hxx files:
|
|
>
|
|
let b:fswitchdst = 'cxx'
|
|
let b:fswitchlocs = 'reg:/include/src/,reg:/include.*/src/,../src'
|
|
<
|
|
|
|
For *.H files:
|
|
>
|
|
let b:fswitchdst = 'C'
|
|
let b:fswitchlocs = 'reg:/include/src/,reg:/include.*/src/,../src'
|
|
<
|
|
|
|
For *.c
|
|
>
|
|
let b:fswitchdst = 'h'
|
|
let b:fswitchlocs = 'reg:/src/include/,reg:|src|include/**|,../include'
|
|
<
|
|
|
|
For *.cpp
|
|
>
|
|
let b:fswitchdst = 'hpp,h'
|
|
let b:fswitchlocs = 'reg:/src/include/,reg:|src|include/**|,../include'
|
|
<
|
|
|
|
For *.cxx
|
|
>
|
|
let b:fswitchdst = 'hxx'
|
|
let b:fswitchlocs = 'reg:/src/include/,reg:|src|include/**|,../include'
|
|
<
|
|
|
|
For *.C
|
|
>
|
|
let b:fswitchdst = 'H'
|
|
let b:fswitchlocs = 'reg:/src/include/,reg:|src|include/**|,../include'
|
|
<
|
|
|
|
==============================================================================
|
|
*fswitch-examples*
|
|
12. Examples~
|
|
*fswitch-example1*
|
|
Let's say you have a C++ codebase and it has the following properties (this
|
|
level of insanity is a bit high but versions that are only slightly saner
|
|
exist in real life):
|
|
|
|
- Source files with {.cpp}, {.cc} and {.C} extensions
|
|
- Header files with {.h} extensions
|
|
- Source files and header files in the same directory
|
|
- Source files in the {src} directory and include files in the
|
|
{include} directory
|
|
- Source files in the {src} directory and include files in the
|
|
{include/name/space} directory (i.e. subdirectories denoted by the
|
|
namespace).
|
|
- Source files in {src/name/space} and header files in
|
|
{include/name/space} (i.e. subdirectories denoted by the namespace).
|
|
|
|
As a final part to this, the "new" way of doing things in this source tree is
|
|
to put header files in a directory noted by namespace and to do the same with
|
|
source files and to name source files with a {cpp} extension.
|
|
|
|
In order to switch between files organized like this, you could specify the
|
|
following:
|
|
>
|
|
augroup mycppfiles
|
|
au!
|
|
au BufEnter *.h let b:fswitchdst = 'cpp,cc,C'
|
|
au BufEnter *.h let b:fswitchlocs = 'reg:/include/src/,reg:/include.*/src/'
|
|
augroup END
|
|
<
|
|
Here the setting of b:fswitchdst to {cpp,cc,C} handles the different C++
|
|
extensions, and prefers to use {cpp} and will create new files with that
|
|
extension.
|
|
|
|
The fswitchlocs setting allows for the following:
|
|
|
|
reg:/include/src/~
|
|
|
|
Take the pathname to the file in the current buffer and
|
|
substitute "src" for "include". This handles the following
|
|
possibilities:
|
|
|
|
- Files are in {include} and {src} respectively
|
|
- Files are in {include/name/space} and {src/name/space}
|
|
respectively
|
|
|
|
reg:/include.*/src/~
|
|
|
|
Take the pathname to the file in the current buffer and
|
|
substitute "src" for "include.*". This handles the following
|
|
possibility:
|
|
|
|
- Files are in {include/name/space} and {src} respectively
|
|
|
|
./~
|
|
This one's a hiddden option. The default location is the
|
|
current directory already so we don't explicitly have to state
|
|
this, but it is the last possibility:
|
|
|
|
- Files are in the same directory
|
|
|
|
*fswitch-example2*
|
|
Here we'll just show a quick example of making use of the globbing aspect of
|
|
the system. Let's say you're working on a {cpp} file and you want to find the
|
|
matching header file, and you have your destination and locations set to the
|
|
following:
|
|
>
|
|
let b:fswitchdst = 'h'
|
|
let b:fswitchlocs = 'reg:|src|include/**|'
|
|
>
|
|
then if you have the a file {src/MyFile.cpp} then this will find the file
|
|
{include/name/space/MyFile.h}.
|
|
|
|
*fswitch-example3*
|
|
At work I'm a Windows C++ programmer and at home I'm a OS X Objective-C
|
|
programmer. There's a problem with this... C++ and Objective-C both use the
|
|
same extension for header files ({.h}).
|
|
|
|
At home I want to be able to use the XCode command line builder in the
|
|
'makeprg' setting when I'm working on the code. I would like this to be set
|
|
when I am on a {.m} file or its companion {.h} file. This is done with the
|
|
following function:
|
|
>
|
|
function! SetMakeForXCode(filename)
|
|
let isObjCFile = 0
|
|
let ext = expand(a:filename . ":e")
|
|
if ext == 'm' || ext == 'mm'
|
|
let isObjCFile = 1
|
|
elseif ext == 'h'
|
|
" Find the companion file
|
|
let companionfile = FSReturnReadableCompanionFilename('%')
|
|
" For some reason expand() doesn't work on the next line
|
|
let companionext = substitute(companionfile, '.*\.', '', '')
|
|
if companionext == 'm' || companionext == 'mm'
|
|
let isObjCFile = 1
|
|
endif
|
|
endif
|
|
if isObjCFile == 1
|
|
setl makeprg=xcodebuild\ -configuration\ Debug
|
|
endif
|
|
endfunction
|
|
<
|
|
Yup, this could have been easier by using the 'filetype' or using some sort of
|
|
|grep| call but I wanted to use this particular hammer. :) I'll probably end
|
|
up switching it to use the 'filetype' instead in the end...
|
|
|
|
==============================================================================
|
|
*fswitch-trouble*
|
|
13. TroubleShooting~
|
|
*fswitch-empty*
|
|
You may get the following error:
|
|
>
|
|
Alternate has evaluated to nothing. See :h fswitch-empty for more info.
|
|
<
|
|
It can happen... This is probably due to the fact that you've got a nicely
|
|
strict set of rules for your locations. With |fswitch-reg| and
|
|
|fswitch-ifrel| and |fswitch-ifabs| you can get rather specific about whether
|
|
or not anything actually happens. If you aren't letting anything really
|
|
happen, it's not going to happen and you're going to end up with an empty
|
|
path.
|
|
|
|
==============================================================================
|
|
*fswitch-changes*
|
|
A. Change History~
|
|
|
|
0.9.5
|
|
- Modified the autocommands to handle the myriad different
|
|
formulations of C++ files per Hong Xu's request. See:
|
|
https://github.com/derekwyatt/vim-fswitch/pull/3
|
|
|
|
0.9.4
|
|
- Added fixes from Alexey Radkov to handle the 'sb' and 'spr' option
|
|
settings as well as the 'switchbuf' option. See:
|
|
https://github.com/derekwyatt/vim-fswitch/pull/2
|
|
- Made small fix to Alexey's fix to keep the 'sb' and 'spr' shadow
|
|
variable local to the buffer and unlet them at the end.
|
|
- I made a quick regression check on this update but did not test
|
|
Alexey's features directly - I trust that he did that :)
|
|
|
|
0.9.3
|
|
- Made sure that there's a check for 7.0 (Thanks Timon Kelter)
|
|
|
|
0.9.2
|
|
- Fix for the splitting commands (Thanks Michael Henry)
|
|
|
|
0.9.1
|
|
- Added :ifrel (|fswitch_ifrel|)
|
|
- Added :ifabs (|fswitch_ifabs|)
|
|
- Added |FSReturnReadableCompanionFilename()|
|
|
- Added |FSReturnCompanionFilenameString()|
|
|
- Changed default settings for .h to use :ifrel instead of :rel
|
|
- Changed default settings for .c and .cpp to use :ifrel instead of
|
|
:rel
|
|
|
|
0.9.0
|
|
- Initial release
|
|
|
|
vim:tw=78:sts=8:ts=8:sw=8:noet:ft=help:
|