![Vim Logo](https://github.com/vim/vim/blob/master/runtime/vimlogo.gif)
# Vim source code #
Here are a few hints for finding your way around the source code. This
doesn't make it less complex than it is, but it gets you started.
You might also want to read
[`:help development`](http://vimdoc.sourceforge.net/htmldoc/develop.html#development).
## Jumping around ##
First of all, use `:make tags` to generate a tags file, so that you can jump
around in the source code.
To jump to a function or variable definition, move the cursor on the name and
use the `CTRL-]` command. Use `CTRL-T` or `CTRL-O` to jump back.
To jump to a file, move the cursor on its name and use the `gf` command.
Most code can be found in a file with an obvious name (incomplete list):
File name | Description
--------------- | -----------
alloc.c | memory management
arglist.c | handling argument list
autocmd.c | autocommands
blob.c | blob data type
buffer.c | manipulating buffers (loaded files)
bufwrite.c | writing a buffer to file
change.c | handling changes to text
cindent.c | C and Lisp indentation
clientserver.c | client server functionality
clipboard.c | handling the clipboard
cmdexpand.c | command-line completion
cmdhist.c | command-line history
debugger.c | vim script debugger
diff.c | diff mode (vimdiff)
drawline.c | drawing a window line
drawscreen.c | drawing the windows
eval.c | expression evaluation
evalbuffer.c | buffer related built-in functions
evalfunc.c | built-in functions
evalvars.c | vim variables
evalwindow.c | window related built-in functions
fileio.c | reading and writing files
filepath.c | dealing with file names and paths
findfile.c | search for files in 'path'
fold.c | folding
getchar.c | getting characters and key mapping
gc.c | garbage collection
help.c | vim help related functions
highlight.c | syntax highlighting
indent.c | text indentation
insexpand.c | Insert mode completion
locale.c | locale/language handling
map.c | mapping and abbreviations
mark.c | marks
match.c | highlight matching
float.c | floating point functions
mbyte.c | multi-byte character handling
memfile.c | storing lines for buffers in a swapfile
memline.c | storing lines for buffers in memory
menu.c | menus
message.c | (error) messages
mouse.c | handling the mouse
ops.c | handling operators ("d", "y", "p")
option.c | options
optionstr.c | handling string options
popupmenu.c | popup menu
popupwin.c | popup window
profiler.c | vim script profiler
quickfix.c | quickfix commands (":make", ":cn")
regexp.c | pattern matching
register.c | handling registers
scriptfile.c | runtime directory handling and sourcing scripts
screen.c | lower level screen functions
search.c | pattern searching
session.c | sessions and views
sign.c | signs
spell.c | spell checking core
spellfile.c | spell file handling
spellsuggest.c | spell correction suggestions
strings.c | string manipulation functions
syntax.c | syntax and other highlighting
tag.c | tags
term.c | terminal handling, termcap codes
testing.c | testing: assert and test functions
textformat.c | text formatting
textobject.c | text objects
textprop.c | text properties
time.c | time and timer functions
typval.c | vim script type/value functions
undo.c | undo and redo
usercmd.c | user defined commands
userfunc.c | user defined functions
viminfo.c | viminfo handling
window.c | handling split windows
## Debugging ##
If you have a reasonable recent version of gdb, you can use the `:Termdebug`
command to debug Vim. See `:help :Termdebug`.
When something is time critical or stepping through code is a hassle, use the
channel logging to create a time-stamped log file. Add lines to the code like
this:
ch_log(NULL, "Value is now %02x", value);
After compiling and starting Vim, do:
:/* vi:set ts=8 sts=4 sw=4 noet:
*
* VIM - Vi IMproved by Bram Moolenaar
*
* Do ":help uganda" in Vim to read copying and usage conditions.
* Do ":help credits" in Vim to see a list of people who contributed.
* See README.txt for an overview of the Vim source code.
*/
/*
* dosinst.h: Common code for dosinst.c and uninstall.c
*/
#include <sys/stat.h>
#include <fcntl.h>
#ifndef UNIX_LINT
# include <io.h>
# include <ctype.h>
# include <direct.h>
# include <windows.h>
# include <shlobj.h>
#endif
#ifdef UNIX_LINT
// Running lint on Unix: Some things are missing.
char *searchpath(char *name);
#endif
#if defined(UNIX_LINT)
# include <unistd.h>
# include <errno.h>
#endif
#include "version.h"
#if defined(UNIX_LINT)
# define vim_mkdir(x, y) mkdir((char *)(x), y)
#else
# define vim_mkdir(x, y) _mkdir((char *)(x))
#endif
#define sleep(n) Sleep((n) * 1000)
// ----------------------------------------
#define BUFSIZE (MAX_PATH*2) // long enough to hold a file name path
#define NUL 0
#define FAIL 0
#define OK 1
#ifndef FALSE
# define FALSE 0
#endif
#ifndef TRUE
# define TRUE 1
#endif
/*
* Modern way of creating registry entries, also works on 64 bit windows when
* compiled as a 32 bit program.
*/
# ifndef KEY_WOW64_64KEY
# define KEY_WOW64_64KEY 0x0100
# endif
# ifndef KEY_WOW64_32KEY
# define KEY_WOW64_32KEY 0x0200
# endif
#ifdef __MINGW32__
# define UNUSED __attribute__((unused))
#else
# define UNUSED
#endif
#define VIM_STARTMENU "Programs\\Vim " VIM_VERSION_SHORT
int interactive; // non-zero when running interactively
/*
* Call malloc() and exit when out of memory.
*/
static void *
alloc(int len)
{
void *p;
p = malloc(len);
if (p == NULL)
{
printf("ERROR: out of memory\n");
exit(1);
}
return p;
}
/*
* The toupper() in Bcc 5.5 doesn't work, use our own implementation.
*/
static int
mytoupper(int c)
{
if (c >= 'a' && c <= 'z')
return c - 'a' + 'A';
return c;
}
static void
myexit(int n)
{
if (!interactive)
{
// Present a prompt, otherwise error messages can't be read.
printf("Press Enter to continue\n");
rewind(stdin);
(void)getchar();
}
exit(n);
}
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL);
/*
* Check if this is a 64-bit OS.
*/
static BOOL
is_64bit_os(void)
{
#ifdef _WIN64
return TRUE;
#else
BOOL bIsWow64 = FALSE;
LPFN_ISWOW64PROCESS pIsWow64Process;
pIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(
GetModuleHandle("kernel32"), "IsWow64Process");
if (pIsWow64Process != NULL)
pIsWow64Process(GetCurrentProcess(), &bIsWow64);
return bIsWow64;
#endif
}
static char *
searchpath(char *name)
{
static char widename[2 * BUFSIZE];
static char location[2 * BUFSIZE + 2];
// There appears to be a bug in FindExecutableA() on Windows NT.
// Use FindExecutableW() instead...
MultiByteToWideChar(CP_ACP, 0, (LPCTSTR)name, -1,
(LPWSTR)widename, BUFSIZE);
if (FindExecutableW((LPCWSTR)widename, (LPCWSTR)"",
(LPWSTR)location) > (HINSTANCE)32)
{
WideCharToMultiByte(CP_ACP, 0, (LPWSTR)location, -1,
(LPSTR)widename, 2 * BUFSIZE, NULL, NULL);
return widename;
}
return NULL;
}
/*
* Call searchpath() and save the result in allocated memory, or return NULL.
*/
static char *
searchpath_save(char *name)
{
char *p;
char *s;
p = searchpath(name);
if (p == NULL)
return NULL;
s = alloc(strlen(p) + 1);
strcpy(s, p);
return s;
}
#ifndef CSIDL_COMMON_PROGRAMS
# define CSIDL_COMMON_PROGRAMS 0x0017
#endif
#ifndef CSIDL_COMMON_DESKTOPDIRECTORY
# define CSIDL_COMMON_DESKTOPDIRECTORY 0x0019
#endif
/*
* Get the path to a requested Windows shell folder.
*
* Return FAIL on error, OK on success
*/
int
get_shell_folder_path(
char *shell_folder_path,
const char *shell_folder_name)
{
/*
* The following code was successfully built with make_mvc.mak.
* The resulting executable worked on Windows 95, Millennium Edition, and
* 2000 Professional. But it was changed after testing...
*/
LPITEMIDLIST pidl = 0; // Pointer to an Item ID list allocated below
LPMALLOC pMalloc; // Pointer to an IMalloc interface
int csidl;
int alt_csidl = -1;
static int desktop_csidl = -1;
static int programs_csidl = -1;
int *pcsidl;
int r;
if (strcmp(shell_folder_name, "desktop") == 0)
{
pcsidl = &desktop_csidl;
csidl = CSIDL_COMMON_DESKTOPDIRECTORY;
alt_csidl = CSIDL_DESKTOP;
}
else if (strncmp(shell_folder_name, "Programs", 8) == 0)
{
pcsidl = &programs_csidl;
csidl = CSIDL_COMMON_PROGRAMS;
alt_csidl = CSIDL_PROGRAMS;
}
else
{
printf("\nERROR (internal) unrecognised shell_folder_name: \"%s\"\n\n",
shell_folder_name);
return FAIL;
}
// Did this stuff before, use the same ID again.
if (*pcsidl >= 0)
{
csidl = *pcsidl;
alt_csidl = -1;
}
retry:
// Initialize pointer to IMalloc interface
if (NOERROR != SHGetMalloc(&pMalloc))
{
printf("\nERROR getting interface for shell_folder_name: \"%s\"\n\n",
shell_folder_name);
return FAIL;
}
// Get an ITEMIDLIST corresponding to the folder code
if (NOERROR != SHGetSpecialFolderLocation(0, csidl, &pidl))
{
if (alt_csidl < 0 || NOERROR != SHGetSpecialFolderLocation(0,
alt_csidl, &pidl))
{
printf("\nERROR getting ITEMIDLIST for shell_folder_name: \"%s\"\n\n",
shell_folder_name);
return FAIL;
}
csidl = alt_csidl;
alt_csidl = -1;
}
// Translate that ITEMIDLIST to a string
r = SHGetPathFromIDList(pidl, shell_folder_path);
// Free the data associated with pidl
pMalloc->lpVtbl->Free(pMalloc, pidl);
// Release the IMalloc interface
pMalloc->lpVtbl->Release(pMalloc);
if (!r)
{
if (alt_csidl >= 0)
{
// We probably get here for Windows 95: the "all users"
// desktop/start menu entry doesn't exist.
csidl = alt_csidl;
alt_csidl = -1;
goto retry;
}
printf("\nERROR translating ITEMIDLIST for shell_folder_name: \"%s\"\n\n",
shell_folder_name);
return FAIL;
}
// If there is an alternative: verify we can write in this directory.
// This should cause a retry when the "all users" directory exists but we
// are a normal user and can't write there.
if (alt_csidl >= 0)
{
char tbuf[BUFSIZE];
FILE *fd;
strcpy(tbuf, shell_folder_path);
strcat(tbuf, "\\vim write test");
fd = fopen(tbuf, "w");
if (fd == NULL)
{
csidl = alt_csidl;
alt_csidl = -1;
goto retry;
}
fclose(fd);
unlink(tbuf);
}
/*
* Keep the found csidl for next time, so that we don't have to do the
* write test every time.
*/
if (*pcsidl < 0)
*pcsidl = csidl;
if (strncmp(shell_folder_name, "Programs\\", 9) == 0)
strcat(shell_folder_path, shell_folder_name + 8);
return OK;
}
/*
* List of targets. The first one (index zero) is used for the default path
* for the batch files.
*/
#define TARGET_COUNT 9
struct
{
char *name; // Vim exe name (without .exe)
char *batname; // batch file name
char *lnkname; // shortcut file name
char *exename; // exe file name
char *exenamearg; // exe file name when using exearg
char *exearg; // argument for vim.exe or gvim.exe
char *oldbat; // path to existing xxx.bat or NULL
char *oldexe; // path to existing xxx.exe or NULL
char batpath[BUFSIZE]; // path of batch file to create; not
// created when it's empty
} targets[TARGET_COUNT] =
{
{"