changeset 15330:a6330a49e036 v8.1.0673

patch 8.1.0673: functionality for signs is spread out over several files commit https://github.com/vim/vim/commit/bbea47075cc4e7826e9f8c203e4272ba023ed7b0 Author: Bram Moolenaar <Bram@vim.org> Date: Tue Jan 1 13:20:31 2019 +0100 patch 8.1.0673: functionality for signs is spread out over several files Problem: Functionality for signs is spread out over several files. Solution: Move most of the sign functionality into sign.c. (Yegappan Lakshmanan, closes #3751)
author Bram Moolenaar <Bram@vim.org>
date Tue, 01 Jan 2019 13:30:09 +0100
parents 9a739a3d145e
children fb2b29e6f5ba
files Filelist src/Make_bc5.mak src/Make_cyg_ming.mak src/Make_dice.mak src/Make_ivc.mak src/Make_manx.mak src/Make_morph.mak src/Make_mvc.mak src/Make_sas.mak src/Make_vms.mms src/Makefile src/README.txt src/buffer.c src/evalfunc.c src/ex_cmds.c src/proto.h src/proto/buffer.pro src/proto/ex_cmds.pro src/proto/sign.pro src/sign.c src/version.c
diffstat 21 files changed, 1957 insertions(+), 1935 deletions(-) [+]
line wrap: on
line diff
--- a/Filelist
+++ b/Filelist
@@ -81,10 +81,11 @@ SRC_ALL =	\
 		src/screen.c \
 		src/search.c \
 		src/sha256.c \
-		src/structs.h \
+		src/sign.c \
 		src/spell.c \
 		src/spell.h \
 		src/spellfile.c \
+		src/structs.h \
 		src/syntax.c \
 		src/tag.c \
 		src/term.c \
@@ -192,6 +193,7 @@ SRC_ALL =	\
 		src/proto/screen.pro \
 		src/proto/search.pro \
 		src/proto/sha256.pro \
+		src/proto/sign.pro \
 		src/proto/spell.pro \
 		src/proto/spellfile.pro \
 		src/proto/syntax.pro \
--- a/src/Make_bc5.mak
+++ b/src/Make_bc5.mak
@@ -581,6 +581,7 @@ vimobj =  \
 	$(OBJDIR)\screen.obj \
 	$(OBJDIR)\search.obj \
 	$(OBJDIR)\sha256.obj \
+	$(OBJDIR)\sign.obj \
 	$(OBJDIR)\spell.obj \
 	$(OBJDIR)\spellfile.obj \
 	$(OBJDIR)\syntax.obj \
--- a/src/Make_cyg_ming.mak
+++ b/src/Make_cyg_ming.mak
@@ -746,6 +746,7 @@ OBJ = \
 	$(OUTDIR)/screen.o \
 	$(OUTDIR)/search.o \
 	$(OUTDIR)/sha256.o \
+	$(OUTDIR)/sign.o \
 	$(OUTDIR)/spell.o \
 	$(OUTDIR)/spellfile.o \
 	$(OUTDIR)/syntax.o \
--- a/src/Make_dice.mak
+++ b/src/Make_dice.mak
@@ -71,6 +71,7 @@ SRC = \
 	screen.c \
 	search.c \
 	sha256.c \
+	sign.c \
 	spell.c \
 	spellfile.c \
 	syntax.c \
@@ -127,6 +128,7 @@ OBJ =	o/arabic.o \
 	o/screen.o \
 	o/search.o \
 	o/sha256.o \
+	o/sign.o \
 	o/spell.o \
 	o/spellfile.o \
 	o/syntax.o \
@@ -252,6 +254,8 @@ o/search.o:	search.c  $(SYMS) regexp.h
 
 o/sha256.o:	sha256.c  $(SYMS)
 
+o/sign.o:	sign.c  $(SYMS)
+
 o/spell.o:	spell.c  $(SYMS) spell.h
 
 o/spellfile.o:	spellfile.c  $(SYMS) spell.h
--- a/src/Make_ivc.mak
+++ b/src/Make_ivc.mak
@@ -257,6 +257,7 @@ LINK32_OBJS= \
 	"$(INTDIR)/screen.obj" \
 	"$(INTDIR)/search.obj" \
 	"$(INTDIR)/sha256.obj" \
+	"$(INTDIR)/sign.obj" \
 	"$(INTDIR)/spell.obj" \
 	"$(INTDIR)/spellfile.obj" \
 	"$(INTDIR)/syntax.obj" \
@@ -675,6 +676,10 @@ SOURCE=.\sha256.c
 # End Source File
 # Begin Source File
 
+SOURCE=.\sign.c
+# End Source File
+# Begin Source File
+
 SOURCE=.\spell.c
 # End Source File
 # Begin Source File
--- a/src/Make_manx.mak
+++ b/src/Make_manx.mak
@@ -81,6 +81,7 @@ SRC =	arabic.c \
 	screen.c \
 	search.c \
 	sha256.c \
+	sign.c \
 	spell.c \
 	spellfile.c \
 	syntax.c \
@@ -139,6 +140,7 @@ OBJ =	obj/arabic.o \
 	obj/screen.o \
 	obj/search.o \
 	obj/sha256.o \
+	obj/sign.o \
 	obj/spell.o \
 	obj/spellfile.o \
 	obj/syntax.o \
@@ -195,6 +197,7 @@ PRO =	proto/arabic.pro \
 	proto/screen.pro \
 	proto/search.pro \
 	proto/sha256.pro \
+	proto/sign.pro \
 	proto/spell.pro \
 	proto/spellfile.pro \
 	proto/syntax.pro \
@@ -389,6 +392,9 @@ obj/search.o:	search.c
 obj/sha256.o:	sha256.c
 	$(CCSYM) $@ sha256.c
 
+obj/sign.o:	sign.c
+	$(CCSYM) $@ sign.c
+
 obj/spell.o:	spell.c
 	$(CCSYM) $@ spell.c
 
--- a/src/Make_morph.mak
+++ b/src/Make_morph.mak
@@ -69,6 +69,7 @@ SRC =	arabic.c						\
 	screen.c						\
 	search.c						\
 	sha256.c						\
+	sign.c							\
 	spell.c							\
 	spellfile.c						\
 	syntax.c						\
--- a/src/Make_mvc.mak
+++ b/src/Make_mvc.mak
@@ -749,6 +749,7 @@ OBJ = \
 	$(OUTDIR)\screen.obj \
 	$(OUTDIR)\search.obj \
 	$(OUTDIR)\sha256.obj \
+	$(OUTDIR)\sign.obj \
 	$(OUTDIR)\spell.obj \
 	$(OUTDIR)\spellfile.obj \
 	$(OUTDIR)\syntax.obj \
@@ -1519,6 +1520,8 @@ lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).l
 
 $(OUTDIR)/sha256.obj:	$(OUTDIR) sha256.c  $(INCL)
 
+$(OUTDIR)/sign.obj:	$(OUTDIR) sign.c  $(INCL)
+
 $(OUTDIR)/spell.obj:	$(OUTDIR) spell.c  $(INCL)
 
 $(OUTDIR)/spellfile.obj:	$(OUTDIR) spellfile.c  $(INCL)
@@ -1664,6 +1667,7 @@ proto.h: \
 	proto/screen.pro \
 	proto/search.pro \
 	proto/sha256.pro \
+	proto/sign.pro \
 	proto/spell.pro \
 	proto/spellfile.pro \
 	proto/syntax.pro \
--- a/src/Make_sas.mak
+++ b/src/Make_sas.mak
@@ -134,6 +134,7 @@ SRC = \
 	screen.c \
 	search.c \
 	sha256.c \
+	sign.c \
 	spell.c \
 	spellfile.c \
 	syntax.c \
@@ -191,6 +192,7 @@ OBJ = \
 	screen.o \
 	search.o \
 	sha256.o \
+	sign.o \
 	spell.o \
 	spellfile.o \
 	syntax.o \
@@ -248,6 +250,7 @@ PRO = \
 	proto/screen.pro \
 	proto/search.pro \
 	proto/sha256.pro \
+	proto/sign.pro \
 	proto/spell.pro \
 	proto/spellfile.pro \
 	proto/syntax.pro \
@@ -404,6 +407,8 @@ search.o:		search.c
 proto/search.pro:	search.c
 sha256.o:		sha256.c
 proto/sha256.pro:	sha256.c
+sign.o:			sign.c
+proto/sign.pro:		sign.c
 spell.o:		spell.c
 proto/spell.pro:	spell.c
 spellfile.o:		spellfile.c
--- a/src/Make_vms.mms
+++ b/src/Make_vms.mms
@@ -302,7 +302,7 @@ ALL_LIBS = $(LIBS) $(GUI_LIB_DIR) $(GUI_
 SRC =	arabic.c beval.obj blowfish.c buffer.c charset.c crypt.c crypt_zip.c dict.c diff.c digraph.c edit.c eval.c evalfunc.c \
 	ex_cmds.c ex_cmds2.c ex_docmd.c ex_eval.c ex_getln.c if_cscope.c if_xcmdsrv.c farsi.c fileio.c fold.c getchar.c \
 	hardcopy.c hashtab.c json.c list.c main.c mark.c menu.c mbyte.c memfile.c memline.c message.c misc1.c \
-	misc2.c move.c normal.c ops.c option.c popupmnu.c quickfix.c regexp.c search.c sha256.c\
+	misc2.c move.c normal.c ops.c option.c popupmnu.c quickfix.c regexp.c search.c sha256.c sign.c \
 	spell.c spellfile.c syntax.c tag.c term.c termlib.c ui.c undo.c userfunc.c version.c screen.c \
 	window.c os_unix.c os_vms.c pathdef.c \
 	$(GUI_SRC) $(PERL_SRC) $(PYTHON_SRC) $(TCL_SRC) \
@@ -313,7 +313,7 @@ OBJ = 	arabic.obj beval.obj blowfish.obj
 	if_xcmdsrv.obj farsi.obj fileio.obj fold.obj getchar.obj hardcopy.obj hashtab.obj json.obj list.obj main.obj mark.obj \
 	menu.obj memfile.obj memline.obj message.obj misc1.obj misc2.obj \
 	move.obj mbyte.obj normal.obj ops.obj option.obj popupmnu.obj quickfix.obj \
-	regexp.obj search.obj sha256.obj spell.obj spellfile.obj syntax.obj tag.obj term.obj termlib.obj \
+	regexp.obj search.obj sha256.obj sign.obj spell.obj spellfile.obj syntax.obj tag.obj term.obj termlib.obj \
 	ui.obj undo.obj userfunc.obj screen.obj version.obj window.obj os_unix.obj \
 	os_vms.obj pathdef.obj if_mzsch.obj\
 	$(GUI_OBJ) $(PERL_OBJ) $(PYTHON_OBJ) $(TCL_OBJ) \
@@ -677,6 +677,10 @@ sha256.obj : sha256.c vim.h [.auto]confi
  ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
  beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h proto.h \
  globals.h farsi.h arabic.h
+sign.obj : sign.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
+ beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h proto.h \
+ globals.h farsi.h arabic.h
 spell.obj : spell.c vim.h [.auto]config.h feature.h os_unix.h \
  ascii.h keymap.h term.h macros.h structs.h regexp.h \
  gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
--- a/src/Makefile
+++ b/src/Makefile
@@ -1626,6 +1626,7 @@ BASIC_SRC = \
 	screen.c \
 	search.c \
 	sha256.c \
+	sign.c \
 	spell.c \
 	spellfile.c \
 	syntax.c \
@@ -1736,6 +1737,7 @@ OBJ_COMMON = \
 	objects/screen.o \
 	objects/search.o \
 	objects/sha256.o \
+	objects/sign.o \
 	objects/spell.o \
 	objects/spellfile.o \
 	objects/syntax.o \
@@ -1870,6 +1872,7 @@ PRO_AUTO = \
 	screen.pro \
 	search.pro \
 	sha256.pro \
+	sign.pro \
 	spell.pro \
 	spellfile.pro \
 	syntax.pro \
@@ -3200,6 +3203,9 @@ objects/search.o: search.c
 objects/sha256.o: sha256.c
 	$(CCC) -o $@ sha256.c
 
+objects/sign.o: sign.c
+	$(CCC) -o $@ sign.c
+
 objects/spell.o: spell.c
 	$(CCC) -o $@ spell.c
 
@@ -3586,6 +3592,10 @@ objects/sha256.o: sha256.c vim.h protode
  auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
  proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
  proto.h globals.h farsi.h arabic.h
+objects/sign.o: sign.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
 objects/spell.o: spell.c vim.h protodef.h auto/config.h feature.h os_unix.h \
  auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
  proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
--- a/src/README.txt
+++ b/src/README.txt
@@ -35,6 +35,7 @@ Most code can be found in a file with an
 	regexp.c	pattern matching
 	screen.c	updating the windows
 	search.c	pattern searching
+	sign.c		signs
 	spell.c		spell checking
 	syntax.c	syntax and other highlighting
 	tag.c		tags
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -5864,642 +5864,6 @@ win_found:
 }
 #endif
 
-#if defined(FEAT_SIGNS) || defined(PROTO)
-static hashtab_T	sg_table;	// sign group (signgroup_T) hashtable
-static int		next_sign_id = 1; // next sign id in the global group
-
-/*
- * Initialize data needed for managing signs
- */
-    void
-init_signs(void)
-{
-    hash_init(&sg_table);		// sign group hash table
-}
-
-/*
- * A new sign in group 'groupname' is added. If the group is not present,
- * create it. Otherwise reference the group.
- */
-    static signgroup_T *
-sign_group_ref(char_u *groupname)
-{
-    hash_T		hash;
-    hashitem_T		*hi;
-    signgroup_T		*group;
-
-    hash = hash_hash(groupname);
-    hi = hash_lookup(&sg_table, groupname, hash);
-    if (HASHITEM_EMPTY(hi))
-    {
-	// new group
-	group = (signgroup_T *)alloc(
-		(unsigned)(sizeof(signgroup_T) + STRLEN(groupname)));
-	if (group == NULL)
-	    return NULL;
-	STRCPY(group->sg_name, groupname);
-	group->refcount = 1;
-	group->next_sign_id = 1;
-	hash_add_item(&sg_table, hi, group->sg_name, hash);
-    }
-    else
-    {
-	// existing group
-	group = HI2SG(hi);
-	group->refcount++;
-    }
-
-    return group;
-}
-
-/*
- * A sign in group 'groupname' is removed. If all the signs in this group are
- * removed, then remove the group.
- */
-    static void
-sign_group_unref(char_u *groupname)
-{
-    hashitem_T		*hi;
-    signgroup_T		*group;
-
-    hi = hash_find(&sg_table, groupname);
-    if (!HASHITEM_EMPTY(hi))
-    {
-	group = HI2SG(hi);
-	group->refcount--;
-	if (group->refcount == 0)
-	{
-	    // All the signs in this group are removed
-	    hash_remove(&sg_table, hi);
-	    vim_free(group);
-	}
-    }
-}
-
-/*
- * Get the next free sign identifier in the specified group
- */
-    int
-sign_group_get_next_signid(buf_T *buf, char_u *groupname)
-{
-    int			id = 1;
-    signgroup_T		*group = NULL;
-    signlist_T		*sign;
-    hashitem_T		*hi;
-    int			found = FALSE;
-
-    if (groupname != NULL)
-    {
-	hi = hash_find(&sg_table, groupname);
-	if (HASHITEM_EMPTY(hi))
-	    return id;
-	group = HI2SG(hi);
-    }
-
-    // Search for the next usuable sign identifier
-    while (!found)
-    {
-	if (group == NULL)
-	    id = next_sign_id++;		// global group
-	else
-	    id = group->next_sign_id++;
-
-	// Check whether this sign is already placed in the buffer
-	found = TRUE;
-	FOR_ALL_SIGNS_IN_BUF(buf, sign)
-	{
-	    if (id == sign->id && sign_in_group(sign, groupname))
-	    {
-		found = FALSE;		// sign identifier is in use
-		break;
-	    }
-	}
-    }
-
-    return id;
-}
-
-/*
- * Insert a new sign into the signlist for buffer 'buf' between the 'prev' and
- * 'next' signs.
- */
-    static void
-insert_sign(
-    buf_T	*buf,		// buffer to store sign in
-    signlist_T	*prev,		// previous sign entry
-    signlist_T	*next,		// next sign entry
-    int		id,		// sign ID
-    char_u	*group,		// sign group; NULL for global group
-    int		prio,		// sign priority
-    linenr_T	lnum,		// line number which gets the mark
-    int		typenr)		// typenr of sign we are adding
-{
-    signlist_T	*newsign;
-
-    newsign = (signlist_T *)lalloc_id((long_u)sizeof(signlist_T), FALSE,
-							aid_insert_sign);
-    if (newsign != NULL)
-    {
-	newsign->id = id;
-	newsign->lnum = lnum;
-	newsign->typenr = typenr;
-	if (group != NULL)
-	{
-	    newsign->group = sign_group_ref(group);
-	    if (newsign->group == NULL)
-	    {
-		vim_free(newsign);
-		return;
-	    }
-	}
-	else
-	    newsign->group = NULL;
-	newsign->priority = prio;
-	newsign->next = next;
-	newsign->prev = prev;
-	if (next != NULL)
-	    next->prev = newsign;
-
-	if (prev == NULL)
-	{
-	    // When adding first sign need to redraw the windows to create the
-	    // column for signs.
-	    if (buf->b_signlist == NULL)
-	    {
-		redraw_buf_later(buf, NOT_VALID);
-		changed_cline_bef_curs();
-	    }
-
-	    // first sign in signlist
-	    buf->b_signlist = newsign;
-#ifdef FEAT_NETBEANS_INTG
-	    if (netbeans_active())
-		buf->b_has_sign_column = TRUE;
-#endif
-	}
-	else
-	    prev->next = newsign;
-    }
-}
-
-/*
- * Insert a new sign sorted by line number and sign priority.
- */
-    static void
-insert_sign_by_lnum_prio(
-    buf_T	*buf,		// buffer to store sign in
-    signlist_T	*prev,		// previous sign entry
-    int		id,		// sign ID
-    char_u	*group,		// sign group; NULL for global group
-    int		prio,		// sign priority
-    linenr_T	lnum,		// line number which gets the mark
-    int		typenr)		// typenr of sign we are adding
-{
-    signlist_T	*sign;
-
-    // keep signs sorted by lnum and by priority: insert new sign at
-    // the proper position in the list for this lnum.
-    while (prev != NULL && prev->lnum == lnum && prev->priority <= prio)
-	prev = prev->prev;
-    if (prev == NULL)
-	sign = buf->b_signlist;
-    else
-	sign = prev->next;
-
-    insert_sign(buf, prev, sign, id, group, prio, lnum, typenr);
-}
-
-/*
- * Returns TRUE if 'sign' is in 'group'.
- * A sign can either be in the global group (sign->group == NULL)
- * or in a named group. If 'group' is '*', then the sign is part of the group.
- */
-    int
-sign_in_group(signlist_T *sign, char_u *group)
-{
-    return ((group != NULL && STRCMP(group, "*") == 0)
-	    || (group == NULL && sign->group == NULL)
-	    || (group != NULL && sign->group != NULL
-				 && STRCMP(group, sign->group->sg_name) == 0));
-}
-
-/*
- * Return information about a sign in a Dict
- */
-    dict_T *
-sign_get_info(signlist_T *sign)
-{
-    dict_T	*d;
-
-    if ((d = dict_alloc_id(aid_sign_getinfo)) == NULL)
-	return NULL;
-    dict_add_number(d, "id", sign->id);
-    dict_add_string(d, "group", (sign->group == NULL) ?
-					(char_u *)"" : sign->group->sg_name);
-    dict_add_number(d, "lnum", sign->lnum);
-    dict_add_string(d, "name", sign_typenr2name(sign->typenr));
-    dict_add_number(d, "priority", sign->priority);
-
-    return d;
-}
-
-/*
- * Add the sign into the signlist. Find the right spot to do it though.
- */
-    void
-buf_addsign(
-    buf_T	*buf,		// buffer to store sign in
-    int		id,		// sign ID
-    char_u	*groupname,	// sign group
-    int		prio,		// sign priority
-    linenr_T	lnum,		// line number which gets the mark
-    int		typenr)		// typenr of sign we are adding
-{
-    signlist_T	*sign;		// a sign in the signlist
-    signlist_T	*prev;		// the previous sign
-
-    prev = NULL;
-    FOR_ALL_SIGNS_IN_BUF(buf, sign)
-    {
-	if (lnum == sign->lnum && id == sign->id &&
-		sign_in_group(sign, groupname))
-	{
-	    // Update an existing sign
-	    sign->typenr = typenr;
-	    return;
-	}
-	else if (lnum < sign->lnum)
-	{
-	    insert_sign_by_lnum_prio(buf, prev, id, groupname, prio,
-								lnum, typenr);
-	    return;
-	}
-	prev = sign;
-    }
-
-    insert_sign_by_lnum_prio(buf, prev, id, groupname, prio, lnum, typenr);
-    return;
-}
-
-/*
- * For an existing, placed sign "markId" change the type to "typenr".
- * Returns the line number of the sign, or zero if the sign is not found.
- */
-    linenr_T
-buf_change_sign_type(
-    buf_T	*buf,		// buffer to store sign in
-    int		markId,		// sign ID
-    char_u	*group,		// sign group
-    int		typenr)		// typenr of sign we are adding
-{
-    signlist_T	*sign;		// a sign in the signlist
-
-    FOR_ALL_SIGNS_IN_BUF(buf, sign)
-    {
-	if (sign->id == markId && sign_in_group(sign, group))
-	{
-	    sign->typenr = typenr;
-	    return sign->lnum;
-	}
-    }
-
-    return (linenr_T)0;
-}
-
-/*
- * Return the type number of the sign at line number 'lnum' in buffer 'buf'
- * which has the attribute specifed by 'type'. Returns 0 if a sign is not found
- * at the line number or it doesn't have the specified attribute.
- */
-    int
-buf_getsigntype(
-    buf_T	*buf,
-    linenr_T	lnum,
-    int		type)	/* SIGN_ICON, SIGN_TEXT, SIGN_ANY, SIGN_LINEHL */
-{
-    signlist_T	*sign;		/* a sign in a b_signlist */
-
-    FOR_ALL_SIGNS_IN_BUF(buf, sign)
-	if (sign->lnum == lnum
-		&& (type == SIGN_ANY
-# ifdef FEAT_SIGN_ICONS
-		    || (type == SIGN_ICON
-			&& sign_get_image(sign->typenr) != NULL)
-# endif
-		    || (type == SIGN_TEXT
-			&& sign_get_text(sign->typenr) != NULL)
-		    || (type == SIGN_LINEHL
-			&& sign_get_attr(sign->typenr, TRUE) != 0)))
-	    return sign->typenr;
-    return 0;
-}
-
-/*
- * Delete sign 'id' in group 'group' from buffer 'buf'.
- * If 'id' is zero, then delete all the signs in group 'group'. Otherwise
- * delete only the specified sign.
- * If 'group' is '*', then delete the sign in all the groups. If 'group' is
- * NULL, then delete the sign in the global group. Otherwise delete the sign in
- * the specified group.
- * Returns the line number of the deleted sign. If multiple signs are deleted,
- * then returns the line number of the last sign deleted.
- */
-    linenr_T
-buf_delsign(
-    buf_T	*buf,		// buffer sign is stored in
-    linenr_T	atlnum,		// sign at this line, 0 - at any line
-    int		id,		// sign id
-    char_u	*group)		// sign group
-{
-    signlist_T	**lastp;	// pointer to pointer to current sign
-    signlist_T	*sign;		// a sign in a b_signlist
-    signlist_T	*next;		// the next sign in a b_signlist
-    linenr_T	lnum;		// line number whose sign was deleted
-
-    lastp = &buf->b_signlist;
-    lnum = 0;
-    for (sign = buf->b_signlist; sign != NULL; sign = next)
-    {
-	next = sign->next;
-	if ((id == 0 || sign->id == id) &&
-		(atlnum == 0 || sign->lnum == atlnum) &&
-		sign_in_group(sign, group))
-
-	{
-	    *lastp = next;
-	    if (next != NULL)
-		next->prev = sign->prev;
-	    lnum = sign->lnum;
-	    if (sign->group != NULL)
-		sign_group_unref(sign->group->sg_name);
-	    vim_free(sign);
-	    update_debug_sign(buf, lnum);
-	    // Check whether only one sign needs to be deleted
-	    // If deleting a sign with a specific identifer in a particular
-	    // group or deleting any sign at a particular line number, delete
-	    // only one sign.
-	    if (group == NULL
-		    || (*group != '*' && id != 0)
-		    || (*group == '*' && atlnum != 0))
-		break;
-	}
-	else
-	    lastp = &sign->next;
-    }
-
-    // When deleted the last sign need to redraw the windows to remove the
-    // sign column.
-    if (buf->b_signlist == NULL)
-    {
-	redraw_buf_later(buf, NOT_VALID);
-	changed_cline_bef_curs();
-    }
-
-    return lnum;
-}
-
-
-/*
- * Find the line number of the sign with the requested id in group 'group'. If
- * the sign does not exist, return 0 as the line number. This will still let
- * the correct file get loaded.
- */
-    int
-buf_findsign(
-    buf_T	*buf,		// buffer to store sign in
-    int		id,		// sign ID
-    char_u	*group)		// sign group
-{
-    signlist_T	*sign;		// a sign in the signlist
-
-    FOR_ALL_SIGNS_IN_BUF(buf, sign)
-	if (sign->id == id && sign_in_group(sign, group))
-	    return sign->lnum;
-
-    return 0;
-}
-
-/*
- * Return the sign at line 'lnum' in buffer 'buf'. Returns NULL if a sign is
- * not found at the line. If 'groupname' is NULL, searches in the global group.
- */
-    static signlist_T *
-buf_getsign_at_line(
-    buf_T	*buf,		// buffer whose sign we are searching for
-    linenr_T	lnum,		// line number of sign
-    char_u	*groupname)	// sign group name
-{
-    signlist_T	*sign;		// a sign in the signlist
-
-    FOR_ALL_SIGNS_IN_BUF(buf, sign)
-	if (sign->lnum == lnum && sign_in_group(sign, groupname))
-	    return sign;
-
-    return NULL;
-}
-
-/*
- * Return the sign with identifier 'id' in group 'group' placed in buffer 'buf'
- */
-    signlist_T *
-buf_getsign_with_id(
-    buf_T	*buf,		// buffer whose sign we are searching for
-    int		id,		// sign identifier
-    char_u	*group)		// sign group
-{
-    signlist_T	*sign;		// a sign in the signlist
-
-    FOR_ALL_SIGNS_IN_BUF(buf, sign)
-	if (sign->id == id && sign_in_group(sign, group))
-	    return sign;
-
-    return NULL;
-}
-
-/*
- * Return the identifier of the sign at line number 'lnum' in buffer 'buf'.
- */
-    int
-buf_findsign_id(
-    buf_T	*buf,		// buffer whose sign we are searching for
-    linenr_T	lnum,		// line number of sign
-    char_u	*groupname)	// sign group name
-{
-    signlist_T	*sign;		// a sign in the signlist
-
-    sign = buf_getsign_at_line(buf, lnum, groupname);
-    if (sign != NULL)
-	return sign->id;
-
-    return 0;
-}
-
-# if defined(FEAT_NETBEANS_INTG) || defined(PROTO)
-/*
- * See if a given type of sign exists on a specific line.
- */
-    int
-buf_findsigntype_id(
-    buf_T	*buf,		/* buffer whose sign we are searching for */
-    linenr_T	lnum,		/* line number of sign */
-    int		typenr)		/* sign type number */
-{
-    signlist_T	*sign;		/* a sign in the signlist */
-
-    FOR_ALL_SIGNS_IN_BUF(buf, sign)
-	if (sign->lnum == lnum && sign->typenr == typenr)
-	    return sign->id;
-
-    return 0;
-}
-
-
-#  if defined(FEAT_SIGN_ICONS) || defined(PROTO)
-/*
- * Return the number of icons on the given line.
- */
-    int
-buf_signcount(buf_T *buf, linenr_T lnum)
-{
-    signlist_T	*sign;		// a sign in the signlist
-    int		count = 0;
-
-    FOR_ALL_SIGNS_IN_BUF(buf, sign)
-	if (sign->lnum == lnum)
-	    if (sign_get_image(sign->typenr) != NULL)
-		count++;
-
-    return count;
-}
-#  endif /* FEAT_SIGN_ICONS */
-# endif /* FEAT_NETBEANS_INTG */
-
-/*
- * Delete signs in group 'group' in buffer "buf". If 'group' is '*', then
- * delete all the signs.
- */
-    void
-buf_delete_signs(buf_T *buf, char_u *group)
-{
-    signlist_T	*sign;
-    signlist_T	**lastp;	// pointer to pointer to current sign
-    signlist_T	*next;
-
-    // When deleting the last sign need to redraw the windows to remove the
-    // sign column. Not when curwin is NULL (this means we're exiting).
-    if (buf->b_signlist != NULL && curwin != NULL)
-    {
-	redraw_buf_later(buf, NOT_VALID);
-	changed_cline_bef_curs();
-    }
-
-    lastp = &buf->b_signlist;
-    for (sign = buf->b_signlist; sign != NULL; sign = next)
-    {
-	next = sign->next;
-	if (sign_in_group(sign, group))
-	{
-	    *lastp = next;
-	    if (next != NULL)
-		next->prev = sign->prev;
-	    if (sign->group != NULL)
-		sign_group_unref(sign->group->sg_name);
-	    vim_free(sign);
-	}
-	else
-	    lastp = &sign->next;
-    }
-}
-
-/*
- * Delete all the signs in the specified group in all the buffers.
- */
-    void
-buf_delete_all_signs(char_u *groupname)
-{
-    buf_T	*buf;		/* buffer we are checking for signs */
-
-    FOR_ALL_BUFFERS(buf)
-	if (buf->b_signlist != NULL)
-	    buf_delete_signs(buf, groupname);
-}
-
-/*
- * List placed signs for "rbuf".  If "rbuf" is NULL do it for all buffers.
- */
-    void
-sign_list_placed(buf_T *rbuf, char_u *sign_group)
-{
-    buf_T	*buf;
-    signlist_T	*sign;
-    char	lbuf[BUFSIZ];
-    char	group[BUFSIZ];
-
-    MSG_PUTS_TITLE(_("\n--- Signs ---"));
-    msg_putchar('\n');
-    if (rbuf == NULL)
-	buf = firstbuf;
-    else
-	buf = rbuf;
-    while (buf != NULL && !got_int)
-    {
-	if (buf->b_signlist != NULL)
-	{
-	    vim_snprintf(lbuf, BUFSIZ, _("Signs for %s:"), buf->b_fname);
-	    MSG_PUTS_ATTR(lbuf, HL_ATTR(HLF_D));
-	    msg_putchar('\n');
-	}
-	FOR_ALL_SIGNS_IN_BUF(buf, sign)
-	{
-	    if (got_int)
-		break;
-	    if (!sign_in_group(sign, sign_group))
-		continue;
-	    if (sign->group != NULL)
-		vim_snprintf(group, BUFSIZ, "  group=%s",
-							sign->group->sg_name);
-	    else
-		group[0] = '\0';
-	    vim_snprintf(lbuf, BUFSIZ, _("    line=%ld  id=%d%s  name=%s "
-							"priority=%d"),
-			   (long)sign->lnum, sign->id, group,
-			   sign_typenr2name(sign->typenr), sign->priority);
-	    MSG_PUTS(lbuf);
-	    msg_putchar('\n');
-	}
-	if (rbuf != NULL)
-	    break;
-	buf = buf->b_next;
-    }
-}
-
-/*
- * Adjust a placed sign for inserted/deleted lines.
- */
-    void
-sign_mark_adjust(
-    linenr_T	line1,
-    linenr_T	line2,
-    long	amount,
-    long	amount_after)
-{
-    signlist_T	*sign;		/* a sign in a b_signlist */
-
-    FOR_ALL_SIGNS_IN_BUF(curbuf, sign)
-    {
-	if (sign->lnum >= line1 && sign->lnum <= line2)
-	{
-	    if (amount == MAXLNUM)
-		sign->lnum = line1;
-	    else
-		sign->lnum += amount;
-	}
-	else if (sign->lnum > line2)
-	    sign->lnum += amount_after;
-    }
-}
-#endif /* FEAT_SIGNS */
-
 /*
  * Set 'buflisted' for curbuf to "on" and trigger autocommands if it changed.
  */
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -4424,24 +4424,6 @@ f_get(typval_T *argvars, typval_T *rettv
 	copy_tv(tv, rettv);
 }
 
-#ifdef FEAT_SIGNS
-/*
- * Returns information about signs placed in a buffer as list of dicts.
- */
-    static void
-get_buffer_signs(buf_T *buf, list_T *l)
-{
-    signlist_T	*sign;
-    dict_T	*d;
-
-    FOR_ALL_SIGNS_IN_BUF(buf, sign)
-    {
-	if ((d = sign_get_info(sign)) != NULL)
-	    list_append_dict(l, d);
-    }
-}
-#endif
-
 /*
  * Returns buffer options, variables and other attributes in a dictionary.
  */
--- a/src/ex_cmds.c
+++ b/src/ex_cmds.c
@@ -7579,1252 +7579,6 @@ ex_helptags(exarg_T *eap)
     }
 }
 
-#if defined(FEAT_SIGNS) || defined(PROTO)
-
-/*
- * Struct to hold the sign properties.
- */
-typedef struct sign sign_T;
-
-struct sign
-{
-    sign_T	*sn_next;	/* next sign in list */
-    int		sn_typenr;	/* type number of sign */
-    char_u	*sn_name;	/* name of sign */
-    char_u	*sn_icon;	/* name of pixmap */
-# ifdef FEAT_SIGN_ICONS
-    void	*sn_image;	/* icon image */
-# endif
-    char_u	*sn_text;	/* text used instead of pixmap */
-    int		sn_line_hl;	/* highlight ID for line */
-    int		sn_text_hl;	/* highlight ID for text */
-};
-
-static sign_T	*first_sign = NULL;
-static int	next_sign_typenr = 1;
-
-static void sign_list_defined(sign_T *sp);
-static void sign_undefine(sign_T *sp, sign_T *sp_prev);
-
-static char *cmds[] = {
-			"define",
-# define SIGNCMD_DEFINE	0
-			"undefine",
-# define SIGNCMD_UNDEFINE 1
-			"list",
-# define SIGNCMD_LIST	2
-			"place",
-# define SIGNCMD_PLACE	3
-			"unplace",
-# define SIGNCMD_UNPLACE 4
-			"jump",
-# define SIGNCMD_JUMP	5
-			NULL
-# define SIGNCMD_LAST	6
-};
-
-/*
- * Find index of a ":sign" subcmd from its name.
- * "*end_cmd" must be writable.
- */
-    static int
-sign_cmd_idx(
-    char_u	*begin_cmd,	/* begin of sign subcmd */
-    char_u	*end_cmd)	/* just after sign subcmd */
-{
-    int		idx;
-    char	save = *end_cmd;
-
-    *end_cmd = NUL;
-    for (idx = 0; ; ++idx)
-	if (cmds[idx] == NULL || STRCMP(begin_cmd, cmds[idx]) == 0)
-	    break;
-    *end_cmd = save;
-    return idx;
-}
-
-/*
- * Find a sign by name. Also returns pointer to the previous sign.
- */
-    static sign_T *
-sign_find(char_u *name, sign_T **sp_prev)
-{
-    sign_T *sp;
-
-    if (sp_prev != NULL)
-	*sp_prev = NULL;
-    for (sp = first_sign; sp != NULL; sp = sp->sn_next)
-    {
-	if (STRCMP(sp->sn_name, name) == 0)
-	    break;
-	if (sp_prev != NULL)
-	    *sp_prev = sp;
-    }
-
-    return sp;
-}
-
-/*
- * Define a new sign or update an existing sign
- */
-    int
-sign_define_by_name(
-	char_u	*name,
-	char_u	*icon,
-	char_u	*linehl,
-	char_u	*text,
-	char_u	*texthl)
-{
-    sign_T	*sp_prev;
-    sign_T	*sp;
-
-    sp = sign_find(name, &sp_prev);
-    if (sp == NULL)
-    {
-	sign_T	*lp;
-	int	start = next_sign_typenr;
-
-	// Allocate a new sign.
-	sp = (sign_T *)alloc_clear_id((unsigned)sizeof(sign_T),
-						aid_sign_define_by_name);
-	if (sp == NULL)
-	    return FAIL;
-
-	// Check that next_sign_typenr is not already being used.
-	// This only happens after wrapping around.  Hopefully
-	// another one got deleted and we can use its number.
-	for (lp = first_sign; lp != NULL; )
-	{
-	    if (lp->sn_typenr == next_sign_typenr)
-	    {
-		++next_sign_typenr;
-		if (next_sign_typenr == MAX_TYPENR)
-		    next_sign_typenr = 1;
-		if (next_sign_typenr == start)
-		{
-		    vim_free(sp);
-		    EMSG(_("E612: Too many signs defined"));
-		    return FAIL;
-		}
-		lp = first_sign;  // start all over
-		continue;
-	    }
-	    lp = lp->sn_next;
-	}
-
-	sp->sn_typenr = next_sign_typenr;
-	if (++next_sign_typenr == MAX_TYPENR)
-	    next_sign_typenr = 1; // wrap around
-
-	sp->sn_name = vim_strsave(name);
-	if (sp->sn_name == NULL)  // out of memory
-	{
-	    vim_free(sp);
-	    return FAIL;
-	}
-
-	// add the new sign to the list of signs
-	if (sp_prev == NULL)
-	    first_sign = sp;
-	else
-	    sp_prev->sn_next = sp;
-    }
-
-    // set values for a defined sign.
-    if (icon != NULL)
-    {
-	vim_free(sp->sn_icon);
-	sp->sn_icon = vim_strsave(icon);
-	backslash_halve(sp->sn_icon);
-# ifdef FEAT_SIGN_ICONS
-	if (gui.in_use)
-	{
-	    out_flush();
-	    if (sp->sn_image != NULL)
-		gui_mch_destroy_sign(sp->sn_image);
-	    sp->sn_image = gui_mch_register_sign(sp->sn_icon);
-	}
-# endif
-    }
-
-    if (text != NULL)
-    {
-	char_u	*s;
-	char_u	*endp;
-	int	cells;
-	int	len;
-
-	endp = text + (int)STRLEN(text);
-	for (s = text; s + 1 < endp; ++s)
-	    if (*s == '\\')
-	    {
-		// Remove a backslash, so that it is possible
-		// to use a space.
-		STRMOVE(s, s + 1);
-		--endp;
-	    }
-# ifdef FEAT_MBYTE
-	// Count cells and check for non-printable chars
-	if (has_mbyte)
-	{
-	    cells = 0;
-	    for (s = text; s < endp; s += (*mb_ptr2len)(s))
-	    {
-		if (!vim_isprintc((*mb_ptr2char)(s)))
-		    break;
-		cells += (*mb_ptr2cells)(s);
-	    }
-	}
-	else
-# endif
-	{
-	    for (s = text; s < endp; ++s)
-		if (!vim_isprintc(*s))
-		    break;
-	    cells = (int)(s - text);
-	}
-	// Currently must be one or two display cells
-	if (s != endp || cells < 1 || cells > 2)
-	{
-	    EMSG2(_("E239: Invalid sign text: %s"), text);
-	    return FAIL;
-	}
-
-	vim_free(sp->sn_text);
-	// Allocate one byte more if we need to pad up
-	// with a space.
-	len = (int)(endp - text + ((cells == 1) ? 1 : 0));
-	sp->sn_text = vim_strnsave(text, len);
-
-	if (sp->sn_text != NULL && cells == 1)
-	    STRCPY(sp->sn_text + len - 1, " ");
-    }
-
-    if (linehl != NULL)
-	sp->sn_line_hl = syn_check_group(linehl, (int)STRLEN(linehl));
-
-    if (texthl != NULL)
-	sp->sn_text_hl = syn_check_group(texthl, (int)STRLEN(texthl));
-
-    return OK;
-}
-
-/*
- * Free the sign specified by 'name'.
- */
-    int
-sign_undefine_by_name(char_u *name)
-{
-    sign_T	*sp_prev;
-    sign_T	*sp;
-
-    sp = sign_find(name, &sp_prev);
-    if (sp == NULL)
-    {
-	EMSG2(_("E155: Unknown sign: %s"), name);
-	return FAIL;
-    }
-    sign_undefine(sp, sp_prev);
-
-    return OK;
-}
-
-/*
- * List the signs matching 'name'
- */
-    static void
-sign_list_by_name(char_u *name)
-{
-    sign_T	*sp;
-
-    sp = sign_find(name, NULL);
-    if (sp != NULL)
-	sign_list_defined(sp);
-    else
-	EMSG2(_("E155: Unknown sign: %s"), name);
-}
-
-/*
- * Place a sign at the specifed file location or update a sign.
- */
-    int
-sign_place(
-	int		*sign_id,
-	char_u		*sign_group,
-	char_u		*sign_name,
-	buf_T		*buf,
-	linenr_T	lnum,
-	int		prio)
-{
-    sign_T	*sp;
-
-    // Check for reserved character '*' in group name
-    if (sign_group != NULL && (*sign_group == '*' || *sign_group == '\0'))
-	return FAIL;
-
-    for (sp = first_sign; sp != NULL; sp = sp->sn_next)
-	if (STRCMP(sp->sn_name, sign_name) == 0)
-	    break;
-    if (sp == NULL)
-    {
-	EMSG2(_("E155: Unknown sign: %s"), sign_name);
-	return FAIL;
-    }
-    if (*sign_id == 0)
-	*sign_id = sign_group_get_next_signid(buf, sign_group);
-
-    if (lnum > 0)
-	// ":sign place {id} line={lnum} name={name} file={fname}":
-	// place a sign
-	buf_addsign(buf, *sign_id, sign_group, prio, lnum, sp->sn_typenr);
-    else
-	// ":sign place {id} file={fname}": change sign type
-	lnum = buf_change_sign_type(buf, *sign_id, sign_group, sp->sn_typenr);
-    if (lnum > 0)
-	update_debug_sign(buf, lnum);
-    else
-    {
-	EMSG2(_("E885: Not possible to change sign %s"), sign_name);
-	return FAIL;
-    }
-
-    return OK;
-}
-
-/*
- * Unplace the specified sign
- */
-    int
-sign_unplace(int sign_id, char_u *sign_group, buf_T *buf, linenr_T atlnum)
-{
-    if (buf->b_signlist == NULL)	// No signs in the buffer
-	return OK;
-
-    if (sign_id == 0)
-    {
-	// Delete all the signs in the specified buffer
-	redraw_buf_later(buf, NOT_VALID);
-	buf_delete_signs(buf, sign_group);
-    }
-    else
-    {
-	linenr_T	lnum;
-
-	// Delete only the specified signs
-	lnum = buf_delsign(buf, atlnum, sign_id, sign_group);
-	if (lnum == 0)
-	    return FAIL;
-    }
-
-    return OK;
-}
-
-/*
- * Unplace the sign at the current cursor line.
- */
-    static void
-sign_unplace_at_cursor(char_u *groupname)
-{
-    int		id = -1;
-
-    id = buf_findsign_id(curwin->w_buffer, curwin->w_cursor.lnum, groupname);
-    if (id > 0)
-	sign_unplace(id, groupname, curwin->w_buffer, curwin->w_cursor.lnum);
-    else
-	EMSG(_("E159: Missing sign number"));
-}
-
-/*
- * sign define command
- *   ":sign define {name} ..."
- */
-    static void
-sign_define_cmd(char_u *sign_name, char_u *cmdline)
-{
-    char_u	*arg;
-    char_u	*p = cmdline;
-    char_u	*icon = NULL;
-    char_u	*text = NULL;
-    char_u	*linehl = NULL;
-    char_u	*texthl = NULL;
-    int failed = FALSE;
-
-    // set values for a defined sign.
-    for (;;)
-    {
-	arg = skipwhite(p);
-	if (*arg == NUL)
-	    break;
-	p = skiptowhite_esc(arg);
-	if (STRNCMP(arg, "icon=", 5) == 0)
-	{
-	    arg += 5;
-	    icon = vim_strnsave(arg, (int)(p - arg));
-	}
-	else if (STRNCMP(arg, "text=", 5) == 0)
-	{
-	    arg += 5;
-	    text = vim_strnsave(arg, (int)(p - arg));
-	}
-	else if (STRNCMP(arg, "linehl=", 7) == 0)
-	{
-	    arg += 7;
-	    linehl = vim_strnsave(arg, (int)(p - arg));
-	}
-	else if (STRNCMP(arg, "texthl=", 7) == 0)
-	{
-	    arg += 7;
-	    texthl = vim_strnsave(arg, (int)(p - arg));
-	}
-	else
-	{
-	    EMSG2(_(e_invarg2), arg);
-	    failed = TRUE;
-	    break;
-	}
-    }
-
-    if (!failed)
-	sign_define_by_name(sign_name, icon, linehl, text, texthl);
-
-    vim_free(icon);
-    vim_free(text);
-    vim_free(linehl);
-    vim_free(texthl);
-}
-
-/*
- * :sign place command
- */
-    static void
-sign_place_cmd(
-	buf_T		*buf,
-	linenr_T	lnum,
-	char_u		*sign_name,
-	int		id,
-	char_u		*group,
-	int		prio)
-{
-    if (id <= 0)
-    {
-	// List signs placed in a file/buffer
-	//   :sign place file={fname}
-	//   :sign place group={group} file={fname}
-	//   :sign place group=* file={fname}
-	//   :sign place buffer={nr}
-	//   :sign place group={group} buffer={nr}
-	//   :sign place group=* buffer={nr}
-	//   :sign place
-	//   :sign place group={group}
-	//   :sign place group=*
-	if (lnum >= 0 || sign_name != NULL ||
-		(group != NULL && *group == '\0'))
-	    EMSG(_(e_invarg));
-	else
-	    sign_list_placed(buf, group);
-    }
-    else
-    {
-	// Place a new sign
-	if (sign_name == NULL || buf == NULL ||
-		(group != NULL && *group == '\0'))
-	{
-	    EMSG(_(e_invarg));
-	    return;
-	}
-
-	sign_place(&id, group, sign_name, buf, lnum, prio);
-    }
-}
-
-/*
- * :sign unplace command
- */
-    static void
-sign_unplace_cmd(
-	buf_T		*buf,
-	linenr_T	lnum,
-	char_u		*sign_name,
-	int		id,
-	char_u		*group)
-{
-    if (lnum >= 0 || sign_name != NULL || (group != NULL && *group == '\0'))
-    {
-	EMSG(_(e_invarg));
-	return;
-    }
-
-    if (id == -2)
-    {
-	if (buf != NULL)
-	    // :sign unplace * file={fname}
-	    // :sign unplace * group={group} file={fname}
-	    // :sign unplace * group=* file={fname}
-	    // :sign unplace * buffer={nr}
-	    // :sign unplace * group={group} buffer={nr}
-	    // :sign unplace * group=* buffer={nr}
-	    sign_unplace(0, group, buf, 0);
-	else
-	    // :sign unplace *
-	    // :sign unplace * group={group}
-	    // :sign unplace * group=*
-	    FOR_ALL_BUFFERS(buf)
-		if (buf->b_signlist != NULL)
-		    buf_delete_signs(buf, group);
-    }
-    else
-    {
-	if (buf != NULL)
-	    // :sign unplace {id} file={fname}
-	    // :sign unplace {id} group={group} file={fname}
-	    // :sign unplace {id} group=* file={fname}
-	    // :sign unplace {id} buffer={nr}
-	    // :sign unplace {id} group={group} buffer={nr}
-	    // :sign unplace {id} group=* buffer={nr}
-	    sign_unplace(id, group, buf, 0);
-	else
-	{
-	    if (id == -1)
-	    {
-		// :sign unplace group={group}
-		// :sign unplace group=*
-		sign_unplace_at_cursor(group);
-	    }
-	    else
-	    {
-		// :sign unplace {id}
-		// :sign unplace {id} group={group}
-		// :sign unplace {id} group=*
-		FOR_ALL_BUFFERS(buf)
-		    sign_unplace(id, group, buf, 0);
-	    }
-	}
-    }
-}
-
-/*
- * Jump to a placed sign
- *   :sign jump {id} file={fname}
- *   :sign jump {id} buffer={nr}
- *   :sign jump {id} group={group} file={fname}
- *   :sign jump {id} group={group} buffer={nr}
- */
-    static void
-sign_jump_cmd(
-	buf_T		*buf,
-	linenr_T	lnum,
-	char_u		*sign_name,
-	int		id,
-	char_u		*group)
-{
-    if (buf == NULL && sign_name == NULL && group == NULL && id == -1)
-    {
-	EMSG(_(e_argreq));
-	return;
-    }
-
-    if (buf == NULL || (group != NULL && *group == '\0') ||
-					lnum >= 0 || sign_name != NULL)
-    {
-	// File or buffer is not specified or an empty group is used
-	// or a line number or a sign name is specified.
-	EMSG(_(e_invarg));
-	return;
-    }
-
-    if ((lnum = buf_findsign(buf, id, group)) <= 0)
-    {
-	EMSGN(_("E157: Invalid sign ID: %ld"), id);
-	return;
-    }
-
-    // goto a sign ...
-    if (buf_jump_open_win(buf) != NULL)
-    {			// ... in a current window
-	curwin->w_cursor.lnum = lnum;
-	check_cursor_lnum();
-	beginline(BL_WHITE);
-    }
-    else
-    {			// ... not currently in a window
-	char_u	*cmd;
-
-	if (buf->b_fname == NULL)
-	{
-	    EMSG(_("E934: Cannot jump to a buffer that does not have a name"));
-	    return;
-	}
-	cmd = alloc((unsigned)STRLEN(buf->b_fname) + 25);
-	if (cmd == NULL)
-	    return;
-	sprintf((char *)cmd, "e +%ld %s", (long)lnum, buf->b_fname);
-	do_cmdline_cmd(cmd);
-	vim_free(cmd);
-    }
-# ifdef FEAT_FOLDING
-    foldOpenCursor();
-# endif
-}
-
-/*
- * Parse the command line arguments for the ":sign place", ":sign unplace" and
- * ":sign jump" commands.
- * The supported arguments are: line={lnum} name={name} group={group}
- * priority={prio} and file={fname} or buffer={nr}.
- */
-    static int
-parse_sign_cmd_args(
-	int	    cmd,
-	char_u	    *arg,
-	char_u	    **sign_name,
-	int	    *signid,
-	char_u	    **group,
-	int	    *prio,
-	buf_T	    **buf,
-	linenr_T    *lnum)
-{
-    char_u	*arg1;
-    char_u	*name;
-    char_u	*filename = NULL;
-
-    // first arg could be placed sign id
-    arg1 = arg;
-    if (VIM_ISDIGIT(*arg))
-    {
-	*signid = getdigits(&arg);
-	if (!VIM_ISWHITE(*arg) && *arg != NUL)
-	{
-	    *signid = -1;
-	    arg = arg1;
-	}
-	else
-	    arg = skipwhite(arg);
-    }
-
-    while (*arg != NUL)
-    {
-	if (STRNCMP(arg, "line=", 5) == 0)
-	{
-	    arg += 5;
-	    *lnum = atoi((char *)arg);
-	    arg = skiptowhite(arg);
-	}
-	else if (STRNCMP(arg, "*", 1) == 0 && cmd == SIGNCMD_UNPLACE)
-	{
-	    if (*signid != -1)
-	    {
-		EMSG(_(e_invarg));
-		return FAIL;
-	    }
-	    *signid = -2;
-	    arg = skiptowhite(arg + 1);
-	}
-	else if (STRNCMP(arg, "name=", 5) == 0)
-	{
-	    arg += 5;
-	    name = arg;
-	    arg = skiptowhite(arg);
-	    if (*arg != NUL)
-		*arg++ = NUL;
-	    while (name[0] == '0' && name[1] != NUL)
-		++name;
-	    *sign_name = name;
-	}
-	else if (STRNCMP(arg, "group=", 6) == 0)
-	{
-	    arg += 6;
-	    *group = arg;
-	    arg = skiptowhite(arg);
-	    if (*arg != NUL)
-		*arg++ = NUL;
-	}
-	else if (STRNCMP(arg, "priority=", 9) == 0)
-	{
-	    arg += 9;
-	    *prio = atoi((char *)arg);
-	    arg = skiptowhite(arg);
-	}
-	else if (STRNCMP(arg, "file=", 5) == 0)
-	{
-	    arg += 5;
-	    filename = arg;
-	    *buf = buflist_findname_exp(arg);
-	    break;
-	}
-	else if (STRNCMP(arg, "buffer=", 7) == 0)
-	{
-	    arg += 7;
-	    filename = arg;
-	    *buf = buflist_findnr((int)getdigits(&arg));
-	    if (*skipwhite(arg) != NUL)
-		EMSG(_(e_trailing));
-	    break;
-	}
-	else
-	{
-	    EMSG(_(e_invarg));
-	    return FAIL;
-	}
-	arg = skipwhite(arg);
-    }
-
-    if (filename != NULL && *buf == NULL)
-    {
-	EMSG2(_("E158: Invalid buffer name: %s"), filename);
-	return FAIL;
-    }
-
-    return OK;
-}
-
-/*
- * ":sign" command
- */
-    void
-ex_sign(exarg_T *eap)
-{
-    char_u	*arg = eap->arg;
-    char_u	*p;
-    int		idx;
-    sign_T	*sp;
-    buf_T	*buf = NULL;
-
-    // Parse the subcommand.
-    p = skiptowhite(arg);
-    idx = sign_cmd_idx(arg, p);
-    if (idx == SIGNCMD_LAST)
-    {
-	EMSG2(_("E160: Unknown sign command: %s"), arg);
-	return;
-    }
-    arg = skipwhite(p);
-
-    if (idx <= SIGNCMD_LIST)
-    {
-	// Define, undefine or list signs.
-	if (idx == SIGNCMD_LIST && *arg == NUL)
-	{
-	    // ":sign list": list all defined signs
-	    for (sp = first_sign; sp != NULL && !got_int; sp = sp->sn_next)
-		sign_list_defined(sp);
-	}
-	else if (*arg == NUL)
-	    EMSG(_("E156: Missing sign name"));
-	else
-	{
-	    char_u	*name;
-
-	    // Isolate the sign name.  If it's a number skip leading zeroes,
-	    // so that "099" and "99" are the same sign.  But keep "0".
-	    p = skiptowhite(arg);
-	    if (*p != NUL)
-		*p++ = NUL;
-	    while (arg[0] == '0' && arg[1] != NUL)
-		++arg;
-	    name = vim_strsave(arg);
-
-	    if (idx == SIGNCMD_DEFINE)
-		sign_define_cmd(name, p);
-	    else if (idx == SIGNCMD_LIST)
-		// ":sign list {name}"
-		sign_list_by_name(name);
-	    else
-		// ":sign undefine {name}"
-		sign_undefine_by_name(name);
-
-	    vim_free(name);
-	    return;
-	}
-    }
-    else
-    {
-	int		id = -1;
-	linenr_T	lnum = -1;
-	char_u		*sign_name = NULL;
-	char_u		*group = NULL;
-	int		prio = SIGN_DEF_PRIO;
-
-	// Parse command line arguments
-	if (parse_sign_cmd_args(idx, arg, &sign_name, &id, &group, &prio,
-							  &buf, &lnum) == FAIL)
-	    return;
-
-	if (idx == SIGNCMD_PLACE)
-	    sign_place_cmd(buf, lnum, sign_name, id, group, prio);
-	else if (idx == SIGNCMD_UNPLACE)
-	    sign_unplace_cmd(buf, lnum, sign_name, id, group);
-	else if (idx == SIGNCMD_JUMP)
-	    sign_jump_cmd(buf, lnum, sign_name, id, group);
-    }
-}
-
-/*
- * Return information about a specified sign
- */
-    static void
-sign_getinfo(sign_T *sp, dict_T *retdict)
-{
-    char_u	*p;
-
-    dict_add_string(retdict, "name", (char_u *)sp->sn_name);
-    if (sp->sn_icon != NULL)
-	dict_add_string(retdict, "icon", (char_u *)sp->sn_icon);
-    if (sp->sn_text != NULL)
-	dict_add_string(retdict, "text", (char_u *)sp->sn_text);
-    if (sp->sn_line_hl > 0)
-    {
-	p = get_highlight_name_ext(NULL, sp->sn_line_hl - 1, FALSE);
-	if (p == NULL)
-	    p = (char_u *)"NONE";
-	dict_add_string(retdict, "linehl", (char_u *)p);
-    }
-    if (sp->sn_text_hl > 0)
-    {
-	p = get_highlight_name_ext(NULL, sp->sn_text_hl - 1, FALSE);
-	if (p == NULL)
-	    p = (char_u *)"NONE";
-	dict_add_string(retdict, "texthl", (char_u *)p);
-    }
-}
-
-/*
- * If 'name' is NULL, return a list of all the defined signs.
- * Otherwise, return information about the specified sign.
- */
-    void
-sign_getlist(char_u *name, list_T *retlist)
-{
-    sign_T	*sp = first_sign;
-    dict_T	*dict;
-
-    if (name != NULL)
-    {
-	sp = sign_find(name, NULL);
-	if (sp == NULL)
-	    return;
-    }
-
-    for (; sp != NULL && !got_int; sp = sp->sn_next)
-    {
-	if ((dict = dict_alloc_id(aid_sign_getlist)) == NULL)
-	    return;
-	if (list_append_dict(retlist, dict) == FAIL)
-	    return;
-	sign_getinfo(sp, dict);
-
-	if (name != NULL)	    // handle only the specified sign
-	    break;
-    }
-}
-
-/*
- * Return information about all the signs placed in a buffer
- */
-    static void
-sign_get_placed_in_buf(
-	buf_T		*buf,
-	linenr_T	lnum,
-	int		sign_id,
-	char_u		*sign_group,
-	list_T		*retlist)
-{
-    dict_T	*d;
-    list_T	*l;
-    signlist_T	*sign;
-    dict_T	*sdict;
-
-    if ((d = dict_alloc_id(aid_sign_getplaced_dict)) == NULL)
-	return;
-    list_append_dict(retlist, d);
-
-    dict_add_number(d, "bufnr", (long)buf->b_fnum);
-
-    if ((l = list_alloc_id(aid_sign_getplaced_list)) == NULL)
-	return;
-    dict_add_list(d, "signs", l);
-
-    FOR_ALL_SIGNS_IN_BUF(buf, sign)
-    {
-	if (!sign_in_group(sign, sign_group))
-	    continue;
-	if ((lnum == 0 && sign_id == 0) ||
-		(sign_id == 0 && lnum == sign->lnum) ||
-		(lnum == 0 && sign_id == sign->id) ||
-		(lnum == sign->lnum && sign_id == sign->id))
-	{
-	    if ((sdict = sign_get_info(sign)) != NULL)
-		list_append_dict(l, sdict);
-	}
-    }
-}
-
-/*
- * Get a list of signs placed in buffer 'buf'. If 'num' is non-zero, return the
- * sign placed at the line number. If 'lnum' is zero, return all the signs
- * placed in 'buf'. If 'buf' is NULL, return signs placed in all the buffers.
- */
-    void
-sign_get_placed(
-	buf_T		*buf,
-	linenr_T	lnum,
-	int		sign_id,
-	char_u		*sign_group,
-	list_T		*retlist)
-{
-    if (buf != NULL)
-	sign_get_placed_in_buf(buf, lnum, sign_id, sign_group, retlist);
-    else
-    {
-	FOR_ALL_BUFFERS(buf)
-	{
-	    if (buf->b_signlist != NULL)
-		sign_get_placed_in_buf(buf, 0, sign_id, sign_group, retlist);
-	}
-    }
-}
-
-# if defined(FEAT_SIGN_ICONS) || defined(PROTO)
-/*
- * Allocate the icons.  Called when the GUI has started.  Allows defining
- * signs before it starts.
- */
-    void
-sign_gui_started(void)
-{
-    sign_T	*sp;
-
-    for (sp = first_sign; sp != NULL; sp = sp->sn_next)
-	if (sp->sn_icon != NULL)
-	    sp->sn_image = gui_mch_register_sign(sp->sn_icon);
-}
-# endif
-
-/*
- * List one sign.
- */
-    static void
-sign_list_defined(sign_T *sp)
-{
-    char_u	*p;
-
-    smsg((char_u *)"sign %s", sp->sn_name);
-    if (sp->sn_icon != NULL)
-    {
-	MSG_PUTS(" icon=");
-	msg_outtrans(sp->sn_icon);
-# ifdef FEAT_SIGN_ICONS
-	if (sp->sn_image == NULL)
-	    MSG_PUTS(_(" (NOT FOUND)"));
-# else
-	MSG_PUTS(_(" (not supported)"));
-# endif
-    }
-    if (sp->sn_text != NULL)
-    {
-	MSG_PUTS(" text=");
-	msg_outtrans(sp->sn_text);
-    }
-    if (sp->sn_line_hl > 0)
-    {
-	MSG_PUTS(" linehl=");
-	p = get_highlight_name_ext(NULL, sp->sn_line_hl - 1, FALSE);
-	if (p == NULL)
-	    MSG_PUTS("NONE");
-	else
-	    msg_puts(p);
-    }
-    if (sp->sn_text_hl > 0)
-    {
-	MSG_PUTS(" texthl=");
-	p = get_highlight_name_ext(NULL, sp->sn_text_hl - 1, FALSE);
-	if (p == NULL)
-	    MSG_PUTS("NONE");
-	else
-	    msg_puts(p);
-    }
-}
-
-/*
- * Undefine a sign and free its memory.
- */
-    static void
-sign_undefine(sign_T *sp, sign_T *sp_prev)
-{
-    vim_free(sp->sn_name);
-    vim_free(sp->sn_icon);
-# ifdef FEAT_SIGN_ICONS
-    if (sp->sn_image != NULL)
-    {
-	out_flush();
-	gui_mch_destroy_sign(sp->sn_image);
-    }
-# endif
-    vim_free(sp->sn_text);
-    if (sp_prev == NULL)
-	first_sign = sp->sn_next;
-    else
-	sp_prev->sn_next = sp->sn_next;
-    vim_free(sp);
-}
-
-/*
- * Get highlighting attribute for sign "typenr".
- * If "line" is TRUE: line highl, if FALSE: text highl.
- */
-    int
-sign_get_attr(int typenr, int line)
-{
-    sign_T	*sp;
-
-    for (sp = first_sign; sp != NULL; sp = sp->sn_next)
-	if (sp->sn_typenr == typenr)
-	{
-	    if (line)
-	    {
-		if (sp->sn_line_hl > 0)
-		    return syn_id2attr(sp->sn_line_hl);
-	    }
-	    else
-	    {
-		if (sp->sn_text_hl > 0)
-		    return syn_id2attr(sp->sn_text_hl);
-	    }
-	    break;
-	}
-    return 0;
-}
-
-/*
- * Get text mark for sign "typenr".
- * Returns NULL if there isn't one.
- */
-    char_u *
-sign_get_text(int typenr)
-{
-    sign_T	*sp;
-
-    for (sp = first_sign; sp != NULL; sp = sp->sn_next)
-	if (sp->sn_typenr == typenr)
-	    return sp->sn_text;
-    return NULL;
-}
-
-# if defined(FEAT_SIGN_ICONS) || defined(PROTO)
-    void *
-sign_get_image(
-    int		typenr)		/* the attribute which may have a sign */
-{
-    sign_T	*sp;
-
-    for (sp = first_sign; sp != NULL; sp = sp->sn_next)
-	if (sp->sn_typenr == typenr)
-	    return sp->sn_image;
-    return NULL;
-}
-# endif
-
-/*
- * Get the name of a sign by its typenr.
- */
-    char_u *
-sign_typenr2name(int typenr)
-{
-    sign_T	*sp;
-
-    for (sp = first_sign; sp != NULL; sp = sp->sn_next)
-	if (sp->sn_typenr == typenr)
-	    return sp->sn_name;
-    return (char_u *)_("[Deleted]");
-}
-
-/*
- * Undefine/free all signs.
- */
-    void
-free_signs(void)
-{
-    while (first_sign != NULL)
-	sign_undefine(first_sign, NULL);
-}
-
-# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
-static enum
-{
-    EXP_SUBCMD,		/* expand :sign sub-commands */
-    EXP_DEFINE,		/* expand :sign define {name} args */
-    EXP_PLACE,		/* expand :sign place {id} args */
-    EXP_UNPLACE,	/* expand :sign unplace" */
-    EXP_SIGN_NAMES	/* expand with name of placed signs */
-} expand_what;
-
-/*
- * Function given to ExpandGeneric() to obtain the sign command
- * expansion.
- */
-    char_u *
-get_sign_name(expand_T *xp UNUSED, int idx)
-{
-    sign_T	*sp;
-    int		current_idx;
-
-    switch (expand_what)
-    {
-    case EXP_SUBCMD:
-	return (char_u *)cmds[idx];
-    case EXP_DEFINE:
-	{
-	    char *define_arg[] =
-	    {
-		"icon=", "linehl=", "text=", "texthl=", NULL
-	    };
-	    return (char_u *)define_arg[idx];
-	}
-    case EXP_PLACE:
-	{
-	    char *place_arg[] =
-	    {
-		"line=", "name=", "group=", "priority=", "file=",
-		"buffer=", NULL
-	    };
-	    return (char_u *)place_arg[idx];
-	}
-    case EXP_UNPLACE:
-	{
-	    char *unplace_arg[] = { "group=", "file=", "buffer=", NULL };
-	    return (char_u *)unplace_arg[idx];
-	}
-    case EXP_SIGN_NAMES:
-	/* Complete with name of signs already defined */
-	current_idx = 0;
-	for (sp = first_sign; sp != NULL; sp = sp->sn_next)
-	    if (current_idx++ == idx)
-		return sp->sn_name;
-	return NULL;
-    default:
-	return NULL;
-    }
-}
-
-/*
- * Handle command line completion for :sign command.
- */
-    void
-set_context_in_sign_cmd(expand_T *xp, char_u *arg)
-{
-    char_u	*p;
-    char_u	*end_subcmd;
-    char_u	*last;
-    int		cmd_idx;
-    char_u	*begin_subcmd_args;
-
-    /* Default: expand subcommands. */
-    xp->xp_context = EXPAND_SIGN;
-    expand_what = EXP_SUBCMD;
-    xp->xp_pattern = arg;
-
-    end_subcmd = skiptowhite(arg);
-    if (*end_subcmd == NUL)
-	/* expand subcmd name
-	 * :sign {subcmd}<CTRL-D>*/
-	return;
-
-    cmd_idx = sign_cmd_idx(arg, end_subcmd);
-
-    /* :sign {subcmd} {subcmd_args}
-     *		      |
-     *		      begin_subcmd_args */
-    begin_subcmd_args = skipwhite(end_subcmd);
-    p = skiptowhite(begin_subcmd_args);
-    if (*p == NUL)
-    {
-	/*
-	 * Expand first argument of subcmd when possible.
-	 * For ":jump {id}" and ":unplace {id}", we could
-	 * possibly expand the ids of all signs already placed.
-	 */
-	xp->xp_pattern = begin_subcmd_args;
-	switch (cmd_idx)
-	{
-	    case SIGNCMD_LIST:
-	    case SIGNCMD_UNDEFINE:
-		/* :sign list <CTRL-D>
-		 * :sign undefine <CTRL-D> */
-		expand_what = EXP_SIGN_NAMES;
-		break;
-	    default:
-		xp->xp_context = EXPAND_NOTHING;
-	}
-	return;
-    }
-
-    /* expand last argument of subcmd */
-
-    /* :sign define {name} {args}...
-     *		    |
-     *		    p */
-
-    /* Loop until reaching last argument. */
-    do
-    {
-	p = skipwhite(p);
-	last = p;
-	p = skiptowhite(p);
-    } while (*p != NUL);
-
-    p = vim_strchr(last, '=');
-
-    /* :sign define {name} {args}... {last}=
-     *				     |	   |
-     *				  last	   p */
-    if (p == NULL)
-    {
-	/* Expand last argument name (before equal sign). */
-	xp->xp_pattern = last;
-	switch (cmd_idx)
-	{
-	    case SIGNCMD_DEFINE:
-		expand_what = EXP_DEFINE;
-		break;
-	    case SIGNCMD_PLACE:
-		expand_what = EXP_PLACE;
-		break;
-	    case SIGNCMD_JUMP:
-	    case SIGNCMD_UNPLACE:
-		expand_what = EXP_UNPLACE;
-		break;
-	    default:
-		xp->xp_context = EXPAND_NOTHING;
-	}
-    }
-    else
-    {
-	/* Expand last argument value (after equal sign). */
-	xp->xp_pattern = p + 1;
-	switch (cmd_idx)
-	{
-	    case SIGNCMD_DEFINE:
-		if (STRNCMP(last, "texthl", p - last) == 0 ||
-		    STRNCMP(last, "linehl", p - last) == 0)
-		    xp->xp_context = EXPAND_HIGHLIGHT;
-		else if (STRNCMP(last, "icon", p - last) == 0)
-		    xp->xp_context = EXPAND_FILES;
-		else
-		    xp->xp_context = EXPAND_NOTHING;
-		break;
-	    case SIGNCMD_PLACE:
-		if (STRNCMP(last, "name", p - last) == 0)
-		    expand_what = EXP_SIGN_NAMES;
-		else
-		    xp->xp_context = EXPAND_NOTHING;
-		break;
-	    default:
-		xp->xp_context = EXPAND_NOTHING;
-	}
-    }
-}
-# endif
-#endif
-
 /*
  * Make the user happy.
  */
--- a/src/proto.h
+++ b/src/proto.h
@@ -172,6 +172,9 @@ void qsort(void *base, size_t elm_count,
 #  include "sha256.pro"
 # endif
 # include "search.pro"
+# ifdef FEAT_SIGNS
+# include "sign.pro"
+# endif
 # include "spell.pro"
 # include "spellfile.pro"
 # include "syntax.pro"
--- a/src/proto/buffer.pro
+++ b/src/proto/buffer.pro
@@ -69,23 +69,6 @@ char_u *buf_spname(buf_T *buf);
 void switch_to_win_for_buf(buf_T *buf, win_T **save_curwinp, tabpage_T **save_curtabp, bufref_T *save_curbuf);
 void restore_win_for_buf(win_T *save_curwin, tabpage_T *save_curtab, bufref_T *save_curbuf);
 int find_win_for_buf(buf_T *buf, win_T **wp, tabpage_T **tp);
-void init_signs(void);
-int sign_group_get_next_signid(buf_T *buf, char_u *groupname);
-int sign_in_group(signlist_T *sign, char_u *group);
-dict_T *sign_get_info(signlist_T *sign);
-void buf_addsign(buf_T *buf, int id, char_u *groupname, int prio, linenr_T lnum, int typenr);
-linenr_T buf_change_sign_type(buf_T *buf, int markId, char_u *group, int typenr);
-int buf_getsigntype(buf_T *buf, linenr_T lnum, int type);
-linenr_T buf_delsign(buf_T *buf, linenr_T atlnum, int id, char_u *group);
-int buf_findsign(buf_T *buf, int id, char_u *group);
-signlist_T *buf_getsign_with_id(buf_T *buf, int id, char_u *group);
-int buf_findsign_id(buf_T *buf, linenr_T lnum, char_u *groupname);
-int buf_findsigntype_id(buf_T *buf, linenr_T lnum, int typenr);
-int buf_signcount(buf_T *buf, linenr_T lnum);
-void buf_delete_signs(buf_T *buf, char_u *group);
-void buf_delete_all_signs(char_u *groupname);
-void sign_list_placed(buf_T *rbuf, char_u *sign_group);
-void sign_mark_adjust(linenr_T line1, linenr_T line2, long amount, long amount_after);
 void set_buflisted(int on);
 int buf_contents_changed(buf_T *buf);
 void wipe_buffer(buf_T *buf, int aucmd);
--- a/src/proto/ex_cmds.pro
+++ b/src/proto/ex_cmds.pro
@@ -54,21 +54,6 @@ void fix_help_buffer(void);
 void ex_exusage(exarg_T *eap);
 void ex_viusage(exarg_T *eap);
 void ex_helptags(exarg_T *eap);
-int sign_define_by_name(char_u *name, char_u *icon, char_u *linehl, char_u *text, char_u *texthl);
-int sign_undefine_by_name(char_u *name);
-int sign_place(int *sign_id, char_u *sign_group, char_u *sign_name, buf_T *buf, linenr_T lnum, int prio);
-int sign_unplace(int sign_id, char_u *sign_group, buf_T *buf, linenr_T atlnum);
-void ex_sign(exarg_T *eap);
-void sign_getlist(char_u *name, list_T *retlist);
-void sign_get_placed(buf_T *buf, linenr_T lnum, int sign_id, char_u *sign_group, list_T *retlist);
-void sign_gui_started(void);
-int sign_get_attr(int typenr, int line);
-char_u *sign_get_text(int typenr);
-void *sign_get_image(int typenr);
-char_u *sign_typenr2name(int typenr);
-void free_signs(void);
-char_u *get_sign_name(expand_T *xp, int idx);
-void set_context_in_sign_cmd(expand_T *xp, char_u *arg);
 void ex_smile(exarg_T *eap);
 void ex_drop(exarg_T *eap);
 char_u *skip_vimgrep_pat(char_u *p, char_u **s, int *flags);
new file mode 100644
--- /dev/null
+++ b/src/proto/sign.pro
@@ -0,0 +1,25 @@
+/* sign.c */
+void init_signs(void);
+int buf_getsigntype(buf_T *buf, linenr_T lnum, int type);
+linenr_T buf_delsign(buf_T *buf, linenr_T atlnum, int id, char_u *group);
+int buf_findsign(buf_T *buf, int id, char_u *group);
+int buf_findsign_id(buf_T *buf, linenr_T lnum, char_u *groupname);
+int buf_findsigntype_id(buf_T *buf, linenr_T lnum, int typenr);
+int buf_signcount(buf_T *buf, linenr_T lnum);
+void buf_delete_signs(buf_T *buf, char_u *group);
+void sign_mark_adjust(linenr_T line1, linenr_T line2, long amount, long amount_after);
+int sign_define_by_name(char_u *name, char_u *icon, char_u *linehl, char_u *text, char_u *texthl);
+int sign_undefine_by_name(char_u *name);
+int sign_place(int *sign_id, char_u *sign_group, char_u *sign_name, buf_T *buf, linenr_T lnum, int prio);
+int sign_unplace(int sign_id, char_u *sign_group, buf_T *buf, linenr_T atlnum);
+void ex_sign(exarg_T *eap);
+void sign_getlist(char_u *name, list_T *retlist);
+void get_buffer_signs(buf_T *buf, list_T *l);
+void sign_get_placed(buf_T *buf, linenr_T lnum, int sign_id, char_u *sign_group, list_T *retlist);
+void sign_gui_started(void);
+int sign_get_attr(int typenr, int line);
+char_u *sign_get_text(int typenr);
+void *sign_get_image(int typenr);
+void free_signs(void);
+char_u *get_sign_name(expand_T *xp, int idx);
+void set_context_in_sign_cmd(expand_T *xp, char_u *arg);
new file mode 100644
--- /dev/null
+++ b/src/sign.c
@@ -0,0 +1,1880 @@
+/* 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.
+ */
+
+/*
+ * sign.c: functions for managing signs
+ */
+
+#include "vim.h"
+
+#if defined(FEAT_SIGNS) || defined(PROTO)
+
+/*
+ * Struct to hold the sign properties.
+ */
+typedef struct sign sign_T;
+
+struct sign
+{
+    sign_T	*sn_next;	/* next sign in list */
+    int		sn_typenr;	/* type number of sign */
+    char_u	*sn_name;	/* name of sign */
+    char_u	*sn_icon;	/* name of pixmap */
+# ifdef FEAT_SIGN_ICONS
+    void	*sn_image;	/* icon image */
+# endif
+    char_u	*sn_text;	/* text used instead of pixmap */
+    int		sn_line_hl;	/* highlight ID for line */
+    int		sn_text_hl;	/* highlight ID for text */
+};
+
+static sign_T	*first_sign = NULL;
+static int	next_sign_typenr = 1;
+
+static void sign_list_defined(sign_T *sp);
+static void sign_undefine(sign_T *sp, sign_T *sp_prev);
+
+static char *cmds[] = {
+			"define",
+# define SIGNCMD_DEFINE	0
+			"undefine",
+# define SIGNCMD_UNDEFINE 1
+			"list",
+# define SIGNCMD_LIST	2
+			"place",
+# define SIGNCMD_PLACE	3
+			"unplace",
+# define SIGNCMD_UNPLACE 4
+			"jump",
+# define SIGNCMD_JUMP	5
+			NULL
+# define SIGNCMD_LAST	6
+};
+
+static hashtab_T	sg_table;	// sign group (signgroup_T) hashtable
+static int		next_sign_id = 1; // next sign id in the global group
+
+/*
+ * Initialize data needed for managing signs
+ */
+    void
+init_signs(void)
+{
+    hash_init(&sg_table);		// sign group hash table
+}
+
+/*
+ * A new sign in group 'groupname' is added. If the group is not present,
+ * create it. Otherwise reference the group.
+ */
+    static signgroup_T *
+sign_group_ref(char_u *groupname)
+{
+    hash_T		hash;
+    hashitem_T		*hi;
+    signgroup_T		*group;
+
+    hash = hash_hash(groupname);
+    hi = hash_lookup(&sg_table, groupname, hash);
+    if (HASHITEM_EMPTY(hi))
+    {
+	// new group
+	group = (signgroup_T *)alloc(
+		(unsigned)(sizeof(signgroup_T) + STRLEN(groupname)));
+	if (group == NULL)
+	    return NULL;
+	STRCPY(group->sg_name, groupname);
+	group->refcount = 1;
+	group->next_sign_id = 1;
+	hash_add_item(&sg_table, hi, group->sg_name, hash);
+    }
+    else
+    {
+	// existing group
+	group = HI2SG(hi);
+	group->refcount++;
+    }
+
+    return group;
+}
+
+/*
+ * A sign in group 'groupname' is removed. If all the signs in this group are
+ * removed, then remove the group.
+ */
+    static void
+sign_group_unref(char_u *groupname)
+{
+    hashitem_T		*hi;
+    signgroup_T		*group;
+
+    hi = hash_find(&sg_table, groupname);
+    if (!HASHITEM_EMPTY(hi))
+    {
+	group = HI2SG(hi);
+	group->refcount--;
+	if (group->refcount == 0)
+	{
+	    // All the signs in this group are removed
+	    hash_remove(&sg_table, hi);
+	    vim_free(group);
+	}
+    }
+}
+
+/*
+ * Returns TRUE if 'sign' is in 'group'.
+ * A sign can either be in the global group (sign->group == NULL)
+ * or in a named group. If 'group' is '*', then the sign is part of the group.
+ */
+    static int
+sign_in_group(signlist_T *sign, char_u *group)
+{
+    return ((group != NULL && STRCMP(group, "*") == 0)
+	    || (group == NULL && sign->group == NULL)
+	    || (group != NULL && sign->group != NULL
+				 && STRCMP(group, sign->group->sg_name) == 0));
+}
+
+/*
+ * Get the next free sign identifier in the specified group
+ */
+    static int
+sign_group_get_next_signid(buf_T *buf, char_u *groupname)
+{
+    int			id = 1;
+    signgroup_T		*group = NULL;
+    signlist_T		*sign;
+    hashitem_T		*hi;
+    int			found = FALSE;
+
+    if (groupname != NULL)
+    {
+	hi = hash_find(&sg_table, groupname);
+	if (HASHITEM_EMPTY(hi))
+	    return id;
+	group = HI2SG(hi);
+    }
+
+    // Search for the next usuable sign identifier
+    while (!found)
+    {
+	if (group == NULL)
+	    id = next_sign_id++;		// global group
+	else
+	    id = group->next_sign_id++;
+
+	// Check whether this sign is already placed in the buffer
+	found = TRUE;
+	FOR_ALL_SIGNS_IN_BUF(buf, sign)
+	{
+	    if (id == sign->id && sign_in_group(sign, groupname))
+	    {
+		found = FALSE;		// sign identifier is in use
+		break;
+	    }
+	}
+    }
+
+    return id;
+}
+
+/*
+ * Insert a new sign into the signlist for buffer 'buf' between the 'prev' and
+ * 'next' signs.
+ */
+    static void
+insert_sign(
+    buf_T	*buf,		// buffer to store sign in
+    signlist_T	*prev,		// previous sign entry
+    signlist_T	*next,		// next sign entry
+    int		id,		// sign ID
+    char_u	*group,		// sign group; NULL for global group
+    int		prio,		// sign priority
+    linenr_T	lnum,		// line number which gets the mark
+    int		typenr)		// typenr of sign we are adding
+{
+    signlist_T	*newsign;
+
+    newsign = (signlist_T *)lalloc_id((long_u)sizeof(signlist_T), FALSE,
+							aid_insert_sign);
+    if (newsign != NULL)
+    {
+	newsign->id = id;
+	newsign->lnum = lnum;
+	newsign->typenr = typenr;
+	if (group != NULL)
+	{
+	    newsign->group = sign_group_ref(group);
+	    if (newsign->group == NULL)
+	    {
+		vim_free(newsign);
+		return;
+	    }
+	}
+	else
+	    newsign->group = NULL;
+	newsign->priority = prio;
+	newsign->next = next;
+	newsign->prev = prev;
+	if (next != NULL)
+	    next->prev = newsign;
+
+	if (prev == NULL)
+	{
+	    // When adding first sign need to redraw the windows to create the
+	    // column for signs.
+	    if (buf->b_signlist == NULL)
+	    {
+		redraw_buf_later(buf, NOT_VALID);
+		changed_cline_bef_curs();
+	    }
+
+	    // first sign in signlist
+	    buf->b_signlist = newsign;
+#ifdef FEAT_NETBEANS_INTG
+	    if (netbeans_active())
+		buf->b_has_sign_column = TRUE;
+#endif
+	}
+	else
+	    prev->next = newsign;
+    }
+}
+
+/*
+ * Insert a new sign sorted by line number and sign priority.
+ */
+    static void
+insert_sign_by_lnum_prio(
+    buf_T	*buf,		// buffer to store sign in
+    signlist_T	*prev,		// previous sign entry
+    int		id,		// sign ID
+    char_u	*group,		// sign group; NULL for global group
+    int		prio,		// sign priority
+    linenr_T	lnum,		// line number which gets the mark
+    int		typenr)		// typenr of sign we are adding
+{
+    signlist_T	*sign;
+
+    // keep signs sorted by lnum and by priority: insert new sign at
+    // the proper position in the list for this lnum.
+    while (prev != NULL && prev->lnum == lnum && prev->priority <= prio)
+	prev = prev->prev;
+    if (prev == NULL)
+	sign = buf->b_signlist;
+    else
+	sign = prev->next;
+
+    insert_sign(buf, prev, sign, id, group, prio, lnum, typenr);
+}
+
+/*
+ * Get the name of a sign by its typenr.
+ */
+    static char_u *
+sign_typenr2name(int typenr)
+{
+    sign_T	*sp;
+
+    for (sp = first_sign; sp != NULL; sp = sp->sn_next)
+	if (sp->sn_typenr == typenr)
+	    return sp->sn_name;
+    return (char_u *)_("[Deleted]");
+}
+
+/*
+ * Return information about a sign in a Dict
+ */
+    static dict_T *
+sign_get_info(signlist_T *sign)
+{
+    dict_T	*d;
+
+    if ((d = dict_alloc_id(aid_sign_getinfo)) == NULL)
+	return NULL;
+    dict_add_number(d, "id", sign->id);
+    dict_add_string(d, "group", (sign->group == NULL) ?
+					(char_u *)"" : sign->group->sg_name);
+    dict_add_number(d, "lnum", sign->lnum);
+    dict_add_string(d, "name", sign_typenr2name(sign->typenr));
+    dict_add_number(d, "priority", sign->priority);
+
+    return d;
+}
+
+/*
+ * Add the sign into the signlist. Find the right spot to do it though.
+ */
+    static void
+buf_addsign(
+    buf_T	*buf,		// buffer to store sign in
+    int		id,		// sign ID
+    char_u	*groupname,	// sign group
+    int		prio,		// sign priority
+    linenr_T	lnum,		// line number which gets the mark
+    int		typenr)		// typenr of sign we are adding
+{
+    signlist_T	*sign;		// a sign in the signlist
+    signlist_T	*prev;		// the previous sign
+
+    prev = NULL;
+    FOR_ALL_SIGNS_IN_BUF(buf, sign)
+    {
+	if (lnum == sign->lnum && id == sign->id &&
+		sign_in_group(sign, groupname))
+	{
+	    // Update an existing sign
+	    sign->typenr = typenr;
+	    return;
+	}
+	else if (lnum < sign->lnum)
+	{
+	    insert_sign_by_lnum_prio(buf, prev, id, groupname, prio,
+								lnum, typenr);
+	    return;
+	}
+	prev = sign;
+    }
+
+    insert_sign_by_lnum_prio(buf, prev, id, groupname, prio, lnum, typenr);
+    return;
+}
+
+/*
+ * For an existing, placed sign "markId" change the type to "typenr".
+ * Returns the line number of the sign, or zero if the sign is not found.
+ */
+    static linenr_T
+buf_change_sign_type(
+    buf_T	*buf,		// buffer to store sign in
+    int		markId,		// sign ID
+    char_u	*group,		// sign group
+    int		typenr)		// typenr of sign we are adding
+{
+    signlist_T	*sign;		// a sign in the signlist
+
+    FOR_ALL_SIGNS_IN_BUF(buf, sign)
+    {
+	if (sign->id == markId && sign_in_group(sign, group))
+	{
+	    sign->typenr = typenr;
+	    return sign->lnum;
+	}
+    }
+
+    return (linenr_T)0;
+}
+
+/*
+ * Return the type number of the sign at line number 'lnum' in buffer 'buf'
+ * which has the attribute specifed by 'type'. Returns 0 if a sign is not found
+ * at the line number or it doesn't have the specified attribute.
+ */
+    int
+buf_getsigntype(
+    buf_T	*buf,
+    linenr_T	lnum,
+    int		type)	/* SIGN_ICON, SIGN_TEXT, SIGN_ANY, SIGN_LINEHL */
+{
+    signlist_T	*sign;		/* a sign in a b_signlist */
+
+    FOR_ALL_SIGNS_IN_BUF(buf, sign)
+	if (sign->lnum == lnum
+		&& (type == SIGN_ANY
+# ifdef FEAT_SIGN_ICONS
+		    || (type == SIGN_ICON
+			&& sign_get_image(sign->typenr) != NULL)
+# endif
+		    || (type == SIGN_TEXT
+			&& sign_get_text(sign->typenr) != NULL)
+		    || (type == SIGN_LINEHL
+			&& sign_get_attr(sign->typenr, TRUE) != 0)))
+	    return sign->typenr;
+    return 0;
+}
+
+/*
+ * Delete sign 'id' in group 'group' from buffer 'buf'.
+ * If 'id' is zero, then delete all the signs in group 'group'. Otherwise
+ * delete only the specified sign.
+ * If 'group' is '*', then delete the sign in all the groups. If 'group' is
+ * NULL, then delete the sign in the global group. Otherwise delete the sign in
+ * the specified group.
+ * Returns the line number of the deleted sign. If multiple signs are deleted,
+ * then returns the line number of the last sign deleted.
+ */
+    linenr_T
+buf_delsign(
+    buf_T	*buf,		// buffer sign is stored in
+    linenr_T	atlnum,		// sign at this line, 0 - at any line
+    int		id,		// sign id
+    char_u	*group)		// sign group
+{
+    signlist_T	**lastp;	// pointer to pointer to current sign
+    signlist_T	*sign;		// a sign in a b_signlist
+    signlist_T	*next;		// the next sign in a b_signlist
+    linenr_T	lnum;		// line number whose sign was deleted
+
+    lastp = &buf->b_signlist;
+    lnum = 0;
+    for (sign = buf->b_signlist; sign != NULL; sign = next)
+    {
+	next = sign->next;
+	if ((id == 0 || sign->id == id) &&
+		(atlnum == 0 || sign->lnum == atlnum) &&
+		sign_in_group(sign, group))
+
+	{
+	    *lastp = next;
+	    if (next != NULL)
+		next->prev = sign->prev;
+	    lnum = sign->lnum;
+	    if (sign->group != NULL)
+		sign_group_unref(sign->group->sg_name);
+	    vim_free(sign);
+	    update_debug_sign(buf, lnum);
+	    // Check whether only one sign needs to be deleted
+	    // If deleting a sign with a specific identifer in a particular
+	    // group or deleting any sign at a particular line number, delete
+	    // only one sign.
+	    if (group == NULL
+		    || (*group != '*' && id != 0)
+		    || (*group == '*' && atlnum != 0))
+		break;
+	}
+	else
+	    lastp = &sign->next;
+    }
+
+    // When deleted the last sign need to redraw the windows to remove the
+    // sign column.
+    if (buf->b_signlist == NULL)
+    {
+	redraw_buf_later(buf, NOT_VALID);
+	changed_cline_bef_curs();
+    }
+
+    return lnum;
+}
+
+
+/*
+ * Find the line number of the sign with the requested id in group 'group'. If
+ * the sign does not exist, return 0 as the line number. This will still let
+ * the correct file get loaded.
+ */
+    int
+buf_findsign(
+    buf_T	*buf,		// buffer to store sign in
+    int		id,		// sign ID
+    char_u	*group)		// sign group
+{
+    signlist_T	*sign;		// a sign in the signlist
+
+    FOR_ALL_SIGNS_IN_BUF(buf, sign)
+	if (sign->id == id && sign_in_group(sign, group))
+	    return sign->lnum;
+
+    return 0;
+}
+
+/*
+ * Return the sign at line 'lnum' in buffer 'buf'. Returns NULL if a sign is
+ * not found at the line. If 'groupname' is NULL, searches in the global group.
+ */
+    static signlist_T *
+buf_getsign_at_line(
+    buf_T	*buf,		// buffer whose sign we are searching for
+    linenr_T	lnum,		// line number of sign
+    char_u	*groupname)	// sign group name
+{
+    signlist_T	*sign;		// a sign in the signlist
+
+    FOR_ALL_SIGNS_IN_BUF(buf, sign)
+	if (sign->lnum == lnum && sign_in_group(sign, groupname))
+	    return sign;
+
+    return NULL;
+}
+
+/*
+ * Return the identifier of the sign at line number 'lnum' in buffer 'buf'.
+ */
+    int
+buf_findsign_id(
+    buf_T	*buf,		// buffer whose sign we are searching for
+    linenr_T	lnum,		// line number of sign
+    char_u	*groupname)	// sign group name
+{
+    signlist_T	*sign;		// a sign in the signlist
+
+    sign = buf_getsign_at_line(buf, lnum, groupname);
+    if (sign != NULL)
+	return sign->id;
+
+    return 0;
+}
+
+# if defined(FEAT_NETBEANS_INTG) || defined(PROTO)
+/*
+ * See if a given type of sign exists on a specific line.
+ */
+    int
+buf_findsigntype_id(
+    buf_T	*buf,		/* buffer whose sign we are searching for */
+    linenr_T	lnum,		/* line number of sign */
+    int		typenr)		/* sign type number */
+{
+    signlist_T	*sign;		/* a sign in the signlist */
+
+    FOR_ALL_SIGNS_IN_BUF(buf, sign)
+	if (sign->lnum == lnum && sign->typenr == typenr)
+	    return sign->id;
+
+    return 0;
+}
+
+
+#  if defined(FEAT_SIGN_ICONS) || defined(PROTO)
+/*
+ * Return the number of icons on the given line.
+ */
+    int
+buf_signcount(buf_T *buf, linenr_T lnum)
+{
+    signlist_T	*sign;		// a sign in the signlist
+    int		count = 0;
+
+    FOR_ALL_SIGNS_IN_BUF(buf, sign)
+	if (sign->lnum == lnum)
+	    if (sign_get_image(sign->typenr) != NULL)
+		count++;
+
+    return count;
+}
+#  endif /* FEAT_SIGN_ICONS */
+# endif /* FEAT_NETBEANS_INTG */
+
+/*
+ * Delete signs in group 'group' in buffer "buf". If 'group' is '*', then
+ * delete all the signs.
+ */
+    void
+buf_delete_signs(buf_T *buf, char_u *group)
+{
+    signlist_T	*sign;
+    signlist_T	**lastp;	// pointer to pointer to current sign
+    signlist_T	*next;
+
+    // When deleting the last sign need to redraw the windows to remove the
+    // sign column. Not when curwin is NULL (this means we're exiting).
+    if (buf->b_signlist != NULL && curwin != NULL)
+    {
+	redraw_buf_later(buf, NOT_VALID);
+	changed_cline_bef_curs();
+    }
+
+    lastp = &buf->b_signlist;
+    for (sign = buf->b_signlist; sign != NULL; sign = next)
+    {
+	next = sign->next;
+	if (sign_in_group(sign, group))
+	{
+	    *lastp = next;
+	    if (next != NULL)
+		next->prev = sign->prev;
+	    if (sign->group != NULL)
+		sign_group_unref(sign->group->sg_name);
+	    vim_free(sign);
+	}
+	else
+	    lastp = &sign->next;
+    }
+}
+
+/*
+ * List placed signs for "rbuf".  If "rbuf" is NULL do it for all buffers.
+ */
+    static void
+sign_list_placed(buf_T *rbuf, char_u *sign_group)
+{
+    buf_T	*buf;
+    signlist_T	*sign;
+    char	lbuf[BUFSIZ];
+    char	group[BUFSIZ];
+
+    MSG_PUTS_TITLE(_("\n--- Signs ---"));
+    msg_putchar('\n');
+    if (rbuf == NULL)
+	buf = firstbuf;
+    else
+	buf = rbuf;
+    while (buf != NULL && !got_int)
+    {
+	if (buf->b_signlist != NULL)
+	{
+	    vim_snprintf(lbuf, BUFSIZ, _("Signs for %s:"), buf->b_fname);
+	    MSG_PUTS_ATTR(lbuf, HL_ATTR(HLF_D));
+	    msg_putchar('\n');
+	}
+	FOR_ALL_SIGNS_IN_BUF(buf, sign)
+	{
+	    if (got_int)
+		break;
+	    if (!sign_in_group(sign, sign_group))
+		continue;
+	    if (sign->group != NULL)
+		vim_snprintf(group, BUFSIZ, "  group=%s",
+							sign->group->sg_name);
+	    else
+		group[0] = '\0';
+	    vim_snprintf(lbuf, BUFSIZ, _("    line=%ld  id=%d%s  name=%s "
+							"priority=%d"),
+			   (long)sign->lnum, sign->id, group,
+			   sign_typenr2name(sign->typenr), sign->priority);
+	    MSG_PUTS(lbuf);
+	    msg_putchar('\n');
+	}
+	if (rbuf != NULL)
+	    break;
+	buf = buf->b_next;
+    }
+}
+
+/*
+ * Adjust a placed sign for inserted/deleted lines.
+ */
+    void
+sign_mark_adjust(
+    linenr_T	line1,
+    linenr_T	line2,
+    long	amount,
+    long	amount_after)
+{
+    signlist_T	*sign;		/* a sign in a b_signlist */
+
+    FOR_ALL_SIGNS_IN_BUF(curbuf, sign)
+    {
+	if (sign->lnum >= line1 && sign->lnum <= line2)
+	{
+	    if (amount == MAXLNUM)
+		sign->lnum = line1;
+	    else
+		sign->lnum += amount;
+	}
+	else if (sign->lnum > line2)
+	    sign->lnum += amount_after;
+    }
+}
+
+/*
+ * Find index of a ":sign" subcmd from its name.
+ * "*end_cmd" must be writable.
+ */
+    static int
+sign_cmd_idx(
+    char_u	*begin_cmd,	/* begin of sign subcmd */
+    char_u	*end_cmd)	/* just after sign subcmd */
+{
+    int		idx;
+    char	save = *end_cmd;
+
+    *end_cmd = NUL;
+    for (idx = 0; ; ++idx)
+	if (cmds[idx] == NULL || STRCMP(begin_cmd, cmds[idx]) == 0)
+	    break;
+    *end_cmd = save;
+    return idx;
+}
+
+/*
+ * Find a sign by name. Also returns pointer to the previous sign.
+ */
+    static sign_T *
+sign_find(char_u *name, sign_T **sp_prev)
+{
+    sign_T *sp;
+
+    if (sp_prev != NULL)
+	*sp_prev = NULL;
+    for (sp = first_sign; sp != NULL; sp = sp->sn_next)
+    {
+	if (STRCMP(sp->sn_name, name) == 0)
+	    break;
+	if (sp_prev != NULL)
+	    *sp_prev = sp;
+    }
+
+    return sp;
+}
+
+/*
+ * Define a new sign or update an existing sign
+ */
+    int
+sign_define_by_name(
+	char_u	*name,
+	char_u	*icon,
+	char_u	*linehl,
+	char_u	*text,
+	char_u	*texthl)
+{
+    sign_T	*sp_prev;
+    sign_T	*sp;
+
+    sp = sign_find(name, &sp_prev);
+    if (sp == NULL)
+    {
+	sign_T	*lp;
+	int	start = next_sign_typenr;
+
+	// Allocate a new sign.
+	sp = (sign_T *)alloc_clear_id((unsigned)sizeof(sign_T),
+						aid_sign_define_by_name);
+	if (sp == NULL)
+	    return FAIL;
+
+	// Check that next_sign_typenr is not already being used.
+	// This only happens after wrapping around.  Hopefully
+	// another one got deleted and we can use its number.
+	for (lp = first_sign; lp != NULL; )
+	{
+	    if (lp->sn_typenr == next_sign_typenr)
+	    {
+		++next_sign_typenr;
+		if (next_sign_typenr == MAX_TYPENR)
+		    next_sign_typenr = 1;
+		if (next_sign_typenr == start)
+		{
+		    vim_free(sp);
+		    EMSG(_("E612: Too many signs defined"));
+		    return FAIL;
+		}
+		lp = first_sign;  // start all over
+		continue;
+	    }
+	    lp = lp->sn_next;
+	}
+
+	sp->sn_typenr = next_sign_typenr;
+	if (++next_sign_typenr == MAX_TYPENR)
+	    next_sign_typenr = 1; // wrap around
+
+	sp->sn_name = vim_strsave(name);
+	if (sp->sn_name == NULL)  // out of memory
+	{
+	    vim_free(sp);
+	    return FAIL;
+	}
+
+	// add the new sign to the list of signs
+	if (sp_prev == NULL)
+	    first_sign = sp;
+	else
+	    sp_prev->sn_next = sp;
+    }
+
+    // set values for a defined sign.
+    if (icon != NULL)
+    {
+	vim_free(sp->sn_icon);
+	sp->sn_icon = vim_strsave(icon);
+	backslash_halve(sp->sn_icon);
+# ifdef FEAT_SIGN_ICONS
+	if (gui.in_use)
+	{
+	    out_flush();
+	    if (sp->sn_image != NULL)
+		gui_mch_destroy_sign(sp->sn_image);
+	    sp->sn_image = gui_mch_register_sign(sp->sn_icon);
+	}
+# endif
+    }
+
+    if (text != NULL)
+    {
+	char_u	*s;
+	char_u	*endp;
+	int	cells;
+	int	len;
+
+	endp = text + (int)STRLEN(text);
+	for (s = text; s + 1 < endp; ++s)
+	    if (*s == '\\')
+	    {
+		// Remove a backslash, so that it is possible
+		// to use a space.
+		STRMOVE(s, s + 1);
+		--endp;
+	    }
+# ifdef FEAT_MBYTE
+	// Count cells and check for non-printable chars
+	if (has_mbyte)
+	{
+	    cells = 0;
+	    for (s = text; s < endp; s += (*mb_ptr2len)(s))
+	    {
+		if (!vim_isprintc((*mb_ptr2char)(s)))
+		    break;
+		cells += (*mb_ptr2cells)(s);
+	    }
+	}
+	else
+# endif
+	{
+	    for (s = text; s < endp; ++s)
+		if (!vim_isprintc(*s))
+		    break;
+	    cells = (int)(s - text);
+	}
+	// Currently must be one or two display cells
+	if (s != endp || cells < 1 || cells > 2)
+	{
+	    EMSG2(_("E239: Invalid sign text: %s"), text);
+	    return FAIL;
+	}
+
+	vim_free(sp->sn_text);
+	// Allocate one byte more if we need to pad up
+	// with a space.
+	len = (int)(endp - text + ((cells == 1) ? 1 : 0));
+	sp->sn_text = vim_strnsave(text, len);
+
+	if (sp->sn_text != NULL && cells == 1)
+	    STRCPY(sp->sn_text + len - 1, " ");
+    }
+
+    if (linehl != NULL)
+	sp->sn_line_hl = syn_check_group(linehl, (int)STRLEN(linehl));
+
+    if (texthl != NULL)
+	sp->sn_text_hl = syn_check_group(texthl, (int)STRLEN(texthl));
+
+    return OK;
+}
+
+/*
+ * Free the sign specified by 'name'.
+ */
+    int
+sign_undefine_by_name(char_u *name)
+{
+    sign_T	*sp_prev;
+    sign_T	*sp;
+
+    sp = sign_find(name, &sp_prev);
+    if (sp == NULL)
+    {
+	EMSG2(_("E155: Unknown sign: %s"), name);
+	return FAIL;
+    }
+    sign_undefine(sp, sp_prev);
+
+    return OK;
+}
+
+/*
+ * List the signs matching 'name'
+ */
+    static void
+sign_list_by_name(char_u *name)
+{
+    sign_T	*sp;
+
+    sp = sign_find(name, NULL);
+    if (sp != NULL)
+	sign_list_defined(sp);
+    else
+	EMSG2(_("E155: Unknown sign: %s"), name);
+}
+
+/*
+ * Place a sign at the specifed file location or update a sign.
+ */
+    int
+sign_place(
+	int		*sign_id,
+	char_u		*sign_group,
+	char_u		*sign_name,
+	buf_T		*buf,
+	linenr_T	lnum,
+	int		prio)
+{
+    sign_T	*sp;
+
+    // Check for reserved character '*' in group name
+    if (sign_group != NULL && (*sign_group == '*' || *sign_group == '\0'))
+	return FAIL;
+
+    for (sp = first_sign; sp != NULL; sp = sp->sn_next)
+	if (STRCMP(sp->sn_name, sign_name) == 0)
+	    break;
+    if (sp == NULL)
+    {
+	EMSG2(_("E155: Unknown sign: %s"), sign_name);
+	return FAIL;
+    }
+    if (*sign_id == 0)
+	*sign_id = sign_group_get_next_signid(buf, sign_group);
+
+    if (lnum > 0)
+	// ":sign place {id} line={lnum} name={name} file={fname}":
+	// place a sign
+	buf_addsign(buf, *sign_id, sign_group, prio, lnum, sp->sn_typenr);
+    else
+	// ":sign place {id} file={fname}": change sign type
+	lnum = buf_change_sign_type(buf, *sign_id, sign_group, sp->sn_typenr);
+    if (lnum > 0)
+	update_debug_sign(buf, lnum);
+    else
+    {
+	EMSG2(_("E885: Not possible to change sign %s"), sign_name);
+	return FAIL;
+    }
+
+    return OK;
+}
+
+/*
+ * Unplace the specified sign
+ */
+    int
+sign_unplace(int sign_id, char_u *sign_group, buf_T *buf, linenr_T atlnum)
+{
+    if (buf->b_signlist == NULL)	// No signs in the buffer
+	return OK;
+
+    if (sign_id == 0)
+    {
+	// Delete all the signs in the specified buffer
+	redraw_buf_later(buf, NOT_VALID);
+	buf_delete_signs(buf, sign_group);
+    }
+    else
+    {
+	linenr_T	lnum;
+
+	// Delete only the specified signs
+	lnum = buf_delsign(buf, atlnum, sign_id, sign_group);
+	if (lnum == 0)
+	    return FAIL;
+    }
+
+    return OK;
+}
+
+/*
+ * Unplace the sign at the current cursor line.
+ */
+    static void
+sign_unplace_at_cursor(char_u *groupname)
+{
+    int		id = -1;
+
+    id = buf_findsign_id(curwin->w_buffer, curwin->w_cursor.lnum, groupname);
+    if (id > 0)
+	sign_unplace(id, groupname, curwin->w_buffer, curwin->w_cursor.lnum);
+    else
+	EMSG(_("E159: Missing sign number"));
+}
+
+/*
+ * sign define command
+ *   ":sign define {name} ..."
+ */
+    static void
+sign_define_cmd(char_u *sign_name, char_u *cmdline)
+{
+    char_u	*arg;
+    char_u	*p = cmdline;
+    char_u	*icon = NULL;
+    char_u	*text = NULL;
+    char_u	*linehl = NULL;
+    char_u	*texthl = NULL;
+    int failed = FALSE;
+
+    // set values for a defined sign.
+    for (;;)
+    {
+	arg = skipwhite(p);
+	if (*arg == NUL)
+	    break;
+	p = skiptowhite_esc(arg);
+	if (STRNCMP(arg, "icon=", 5) == 0)
+	{
+	    arg += 5;
+	    icon = vim_strnsave(arg, (int)(p - arg));
+	}
+	else if (STRNCMP(arg, "text=", 5) == 0)
+	{
+	    arg += 5;
+	    text = vim_strnsave(arg, (int)(p - arg));
+	}
+	else if (STRNCMP(arg, "linehl=", 7) == 0)
+	{
+	    arg += 7;
+	    linehl = vim_strnsave(arg, (int)(p - arg));
+	}
+	else if (STRNCMP(arg, "texthl=", 7) == 0)
+	{
+	    arg += 7;
+	    texthl = vim_strnsave(arg, (int)(p - arg));
+	}
+	else
+	{
+	    EMSG2(_(e_invarg2), arg);
+	    failed = TRUE;
+	    break;
+	}
+    }
+
+    if (!failed)
+	sign_define_by_name(sign_name, icon, linehl, text, texthl);
+
+    vim_free(icon);
+    vim_free(text);
+    vim_free(linehl);
+    vim_free(texthl);
+}
+
+/*
+ * :sign place command
+ */
+    static void
+sign_place_cmd(
+	buf_T		*buf,
+	linenr_T	lnum,
+	char_u		*sign_name,
+	int		id,
+	char_u		*group,
+	int		prio)
+{
+    if (id <= 0)
+    {
+	// List signs placed in a file/buffer
+	//   :sign place file={fname}
+	//   :sign place group={group} file={fname}
+	//   :sign place group=* file={fname}
+	//   :sign place buffer={nr}
+	//   :sign place group={group} buffer={nr}
+	//   :sign place group=* buffer={nr}
+	//   :sign place
+	//   :sign place group={group}
+	//   :sign place group=*
+	if (lnum >= 0 || sign_name != NULL ||
+		(group != NULL && *group == '\0'))
+	    EMSG(_(e_invarg));
+	else
+	    sign_list_placed(buf, group);
+    }
+    else
+    {
+	// Place a new sign
+	if (sign_name == NULL || buf == NULL ||
+		(group != NULL && *group == '\0'))
+	{
+	    EMSG(_(e_invarg));
+	    return;
+	}
+
+	sign_place(&id, group, sign_name, buf, lnum, prio);
+    }
+}
+
+/*
+ * :sign unplace command
+ */
+    static void
+sign_unplace_cmd(
+	buf_T		*buf,
+	linenr_T	lnum,
+	char_u		*sign_name,
+	int		id,
+	char_u		*group)
+{
+    if (lnum >= 0 || sign_name != NULL || (group != NULL && *group == '\0'))
+    {
+	EMSG(_(e_invarg));
+	return;
+    }
+
+    if (id == -2)
+    {
+	if (buf != NULL)
+	    // :sign unplace * file={fname}
+	    // :sign unplace * group={group} file={fname}
+	    // :sign unplace * group=* file={fname}
+	    // :sign unplace * buffer={nr}
+	    // :sign unplace * group={group} buffer={nr}
+	    // :sign unplace * group=* buffer={nr}
+	    sign_unplace(0, group, buf, 0);
+	else
+	    // :sign unplace *
+	    // :sign unplace * group={group}
+	    // :sign unplace * group=*
+	    FOR_ALL_BUFFERS(buf)
+		if (buf->b_signlist != NULL)
+		    buf_delete_signs(buf, group);
+    }
+    else
+    {
+	if (buf != NULL)
+	    // :sign unplace {id} file={fname}
+	    // :sign unplace {id} group={group} file={fname}
+	    // :sign unplace {id} group=* file={fname}
+	    // :sign unplace {id} buffer={nr}
+	    // :sign unplace {id} group={group} buffer={nr}
+	    // :sign unplace {id} group=* buffer={nr}
+	    sign_unplace(id, group, buf, 0);
+	else
+	{
+	    if (id == -1)
+	    {
+		// :sign unplace group={group}
+		// :sign unplace group=*
+		sign_unplace_at_cursor(group);
+	    }
+	    else
+	    {
+		// :sign unplace {id}
+		// :sign unplace {id} group={group}
+		// :sign unplace {id} group=*
+		FOR_ALL_BUFFERS(buf)
+		    sign_unplace(id, group, buf, 0);
+	    }
+	}
+    }
+}
+
+/*
+ * Jump to a placed sign
+ *   :sign jump {id} file={fname}
+ *   :sign jump {id} buffer={nr}
+ *   :sign jump {id} group={group} file={fname}
+ *   :sign jump {id} group={group} buffer={nr}
+ */
+    static void
+sign_jump_cmd(
+	buf_T		*buf,
+	linenr_T	lnum,
+	char_u		*sign_name,
+	int		id,
+	char_u		*group)
+{
+    if (buf == NULL && sign_name == NULL && group == NULL && id == -1)
+    {
+	EMSG(_(e_argreq));
+	return;
+    }
+
+    if (buf == NULL || (group != NULL && *group == '\0') ||
+					lnum >= 0 || sign_name != NULL)
+    {
+	// File or buffer is not specified or an empty group is used
+	// or a line number or a sign name is specified.
+	EMSG(_(e_invarg));
+	return;
+    }
+
+    if ((lnum = buf_findsign(buf, id, group)) <= 0)
+    {
+	EMSGN(_("E157: Invalid sign ID: %ld"), id);
+	return;
+    }
+
+    // goto a sign ...
+    if (buf_jump_open_win(buf) != NULL)
+    {			// ... in a current window
+	curwin->w_cursor.lnum = lnum;
+	check_cursor_lnum();
+	beginline(BL_WHITE);
+    }
+    else
+    {			// ... not currently in a window
+	char_u	*cmd;
+
+	if (buf->b_fname == NULL)
+	{
+	    EMSG(_("E934: Cannot jump to a buffer that does not have a name"));
+	    return;
+	}
+	cmd = alloc((unsigned)STRLEN(buf->b_fname) + 25);
+	if (cmd == NULL)
+	    return;
+	sprintf((char *)cmd, "e +%ld %s", (long)lnum, buf->b_fname);
+	do_cmdline_cmd(cmd);
+	vim_free(cmd);
+    }
+# ifdef FEAT_FOLDING
+    foldOpenCursor();
+# endif
+}
+
+/*
+ * Parse the command line arguments for the ":sign place", ":sign unplace" and
+ * ":sign jump" commands.
+ * The supported arguments are: line={lnum} name={name} group={group}
+ * priority={prio} and file={fname} or buffer={nr}.
+ */
+    static int
+parse_sign_cmd_args(
+	int	    cmd,
+	char_u	    *arg,
+	char_u	    **sign_name,
+	int	    *signid,
+	char_u	    **group,
+	int	    *prio,
+	buf_T	    **buf,
+	linenr_T    *lnum)
+{
+    char_u	*arg1;
+    char_u	*name;
+    char_u	*filename = NULL;
+
+    // first arg could be placed sign id
+    arg1 = arg;
+    if (VIM_ISDIGIT(*arg))
+    {
+	*signid = getdigits(&arg);
+	if (!VIM_ISWHITE(*arg) && *arg != NUL)
+	{
+	    *signid = -1;
+	    arg = arg1;
+	}
+	else
+	    arg = skipwhite(arg);
+    }
+
+    while (*arg != NUL)
+    {
+	if (STRNCMP(arg, "line=", 5) == 0)
+	{
+	    arg += 5;
+	    *lnum = atoi((char *)arg);
+	    arg = skiptowhite(arg);
+	}
+	else if (STRNCMP(arg, "*", 1) == 0 && cmd == SIGNCMD_UNPLACE)
+	{
+	    if (*signid != -1)
+	    {
+		EMSG(_(e_invarg));
+		return FAIL;
+	    }
+	    *signid = -2;
+	    arg = skiptowhite(arg + 1);
+	}
+	else if (STRNCMP(arg, "name=", 5) == 0)
+	{
+	    arg += 5;
+	    name = arg;
+	    arg = skiptowhite(arg);
+	    if (*arg != NUL)
+		*arg++ = NUL;
+	    while (name[0] == '0' && name[1] != NUL)
+		++name;
+	    *sign_name = name;
+	}
+	else if (STRNCMP(arg, "group=", 6) == 0)
+	{
+	    arg += 6;
+	    *group = arg;
+	    arg = skiptowhite(arg);
+	    if (*arg != NUL)
+		*arg++ = NUL;
+	}
+	else if (STRNCMP(arg, "priority=", 9) == 0)
+	{
+	    arg += 9;
+	    *prio = atoi((char *)arg);
+	    arg = skiptowhite(arg);
+	}
+	else if (STRNCMP(arg, "file=", 5) == 0)
+	{
+	    arg += 5;
+	    filename = arg;
+	    *buf = buflist_findname_exp(arg);
+	    break;
+	}
+	else if (STRNCMP(arg, "buffer=", 7) == 0)
+	{
+	    arg += 7;
+	    filename = arg;
+	    *buf = buflist_findnr((int)getdigits(&arg));
+	    if (*skipwhite(arg) != NUL)
+		EMSG(_(e_trailing));
+	    break;
+	}
+	else
+	{
+	    EMSG(_(e_invarg));
+	    return FAIL;
+	}
+	arg = skipwhite(arg);
+    }
+
+    if (filename != NULL && *buf == NULL)
+    {
+	EMSG2(_("E158: Invalid buffer name: %s"), filename);
+	return FAIL;
+    }
+
+    return OK;
+}
+
+/*
+ * ":sign" command
+ */
+    void
+ex_sign(exarg_T *eap)
+{
+    char_u	*arg = eap->arg;
+    char_u	*p;
+    int		idx;
+    sign_T	*sp;
+    buf_T	*buf = NULL;
+
+    // Parse the subcommand.
+    p = skiptowhite(arg);
+    idx = sign_cmd_idx(arg, p);
+    if (idx == SIGNCMD_LAST)
+    {
+	EMSG2(_("E160: Unknown sign command: %s"), arg);
+	return;
+    }
+    arg = skipwhite(p);
+
+    if (idx <= SIGNCMD_LIST)
+    {
+	// Define, undefine or list signs.
+	if (idx == SIGNCMD_LIST && *arg == NUL)
+	{
+	    // ":sign list": list all defined signs
+	    for (sp = first_sign; sp != NULL && !got_int; sp = sp->sn_next)
+		sign_list_defined(sp);
+	}
+	else if (*arg == NUL)
+	    EMSG(_("E156: Missing sign name"));
+	else
+	{
+	    char_u	*name;
+
+	    // Isolate the sign name.  If it's a number skip leading zeroes,
+	    // so that "099" and "99" are the same sign.  But keep "0".
+	    p = skiptowhite(arg);
+	    if (*p != NUL)
+		*p++ = NUL;
+	    while (arg[0] == '0' && arg[1] != NUL)
+		++arg;
+	    name = vim_strsave(arg);
+
+	    if (idx == SIGNCMD_DEFINE)
+		sign_define_cmd(name, p);
+	    else if (idx == SIGNCMD_LIST)
+		// ":sign list {name}"
+		sign_list_by_name(name);
+	    else
+		// ":sign undefine {name}"
+		sign_undefine_by_name(name);
+
+	    vim_free(name);
+	    return;
+	}
+    }
+    else
+    {
+	int		id = -1;
+	linenr_T	lnum = -1;
+	char_u		*sign_name = NULL;
+	char_u		*group = NULL;
+	int		prio = SIGN_DEF_PRIO;
+
+	// Parse command line arguments
+	if (parse_sign_cmd_args(idx, arg, &sign_name, &id, &group, &prio,
+							  &buf, &lnum) == FAIL)
+	    return;
+
+	if (idx == SIGNCMD_PLACE)
+	    sign_place_cmd(buf, lnum, sign_name, id, group, prio);
+	else if (idx == SIGNCMD_UNPLACE)
+	    sign_unplace_cmd(buf, lnum, sign_name, id, group);
+	else if (idx == SIGNCMD_JUMP)
+	    sign_jump_cmd(buf, lnum, sign_name, id, group);
+    }
+}
+
+/*
+ * Return information about a specified sign
+ */
+    static void
+sign_getinfo(sign_T *sp, dict_T *retdict)
+{
+    char_u	*p;
+
+    dict_add_string(retdict, "name", (char_u *)sp->sn_name);
+    if (sp->sn_icon != NULL)
+	dict_add_string(retdict, "icon", (char_u *)sp->sn_icon);
+    if (sp->sn_text != NULL)
+	dict_add_string(retdict, "text", (char_u *)sp->sn_text);
+    if (sp->sn_line_hl > 0)
+    {
+	p = get_highlight_name_ext(NULL, sp->sn_line_hl - 1, FALSE);
+	if (p == NULL)
+	    p = (char_u *)"NONE";
+	dict_add_string(retdict, "linehl", (char_u *)p);
+    }
+    if (sp->sn_text_hl > 0)
+    {
+	p = get_highlight_name_ext(NULL, sp->sn_text_hl - 1, FALSE);
+	if (p == NULL)
+	    p = (char_u *)"NONE";
+	dict_add_string(retdict, "texthl", (char_u *)p);
+    }
+}
+
+/*
+ * If 'name' is NULL, return a list of all the defined signs.
+ * Otherwise, return information about the specified sign.
+ */
+    void
+sign_getlist(char_u *name, list_T *retlist)
+{
+    sign_T	*sp = first_sign;
+    dict_T	*dict;
+
+    if (name != NULL)
+    {
+	sp = sign_find(name, NULL);
+	if (sp == NULL)
+	    return;
+    }
+
+    for (; sp != NULL && !got_int; sp = sp->sn_next)
+    {
+	if ((dict = dict_alloc_id(aid_sign_getlist)) == NULL)
+	    return;
+	if (list_append_dict(retlist, dict) == FAIL)
+	    return;
+	sign_getinfo(sp, dict);
+
+	if (name != NULL)	    // handle only the specified sign
+	    break;
+    }
+}
+
+/*
+ * Returns information about signs placed in a buffer as list of dicts.
+ */
+    void
+get_buffer_signs(buf_T *buf, list_T *l)
+{
+    signlist_T	*sign;
+    dict_T	*d;
+
+    FOR_ALL_SIGNS_IN_BUF(buf, sign)
+    {
+	if ((d = sign_get_info(sign)) != NULL)
+	    list_append_dict(l, d);
+    }
+}
+
+/*
+ * Return information about all the signs placed in a buffer
+ */
+    static void
+sign_get_placed_in_buf(
+	buf_T		*buf,
+	linenr_T	lnum,
+	int		sign_id,
+	char_u		*sign_group,
+	list_T		*retlist)
+{
+    dict_T	*d;
+    list_T	*l;
+    signlist_T	*sign;
+    dict_T	*sdict;
+
+    if ((d = dict_alloc_id(aid_sign_getplaced_dict)) == NULL)
+	return;
+    list_append_dict(retlist, d);
+
+    dict_add_number(d, "bufnr", (long)buf->b_fnum);
+
+    if ((l = list_alloc_id(aid_sign_getplaced_list)) == NULL)
+	return;
+    dict_add_list(d, "signs", l);
+
+    FOR_ALL_SIGNS_IN_BUF(buf, sign)
+    {
+	if (!sign_in_group(sign, sign_group))
+	    continue;
+	if ((lnum == 0 && sign_id == 0) ||
+		(sign_id == 0 && lnum == sign->lnum) ||
+		(lnum == 0 && sign_id == sign->id) ||
+		(lnum == sign->lnum && sign_id == sign->id))
+	{
+	    if ((sdict = sign_get_info(sign)) != NULL)
+		list_append_dict(l, sdict);
+	}
+    }
+}
+
+/*
+ * Get a list of signs placed in buffer 'buf'. If 'num' is non-zero, return the
+ * sign placed at the line number. If 'lnum' is zero, return all the signs
+ * placed in 'buf'. If 'buf' is NULL, return signs placed in all the buffers.
+ */
+    void
+sign_get_placed(
+	buf_T		*buf,
+	linenr_T	lnum,
+	int		sign_id,
+	char_u		*sign_group,
+	list_T		*retlist)
+{
+    if (buf != NULL)
+	sign_get_placed_in_buf(buf, lnum, sign_id, sign_group, retlist);
+    else
+    {
+	FOR_ALL_BUFFERS(buf)
+	{
+	    if (buf->b_signlist != NULL)
+		sign_get_placed_in_buf(buf, 0, sign_id, sign_group, retlist);
+	}
+    }
+}
+
+# if defined(FEAT_SIGN_ICONS) || defined(PROTO)
+/*
+ * Allocate the icons.  Called when the GUI has started.  Allows defining
+ * signs before it starts.
+ */
+    void
+sign_gui_started(void)
+{
+    sign_T	*sp;
+
+    for (sp = first_sign; sp != NULL; sp = sp->sn_next)
+	if (sp->sn_icon != NULL)
+	    sp->sn_image = gui_mch_register_sign(sp->sn_icon);
+}
+# endif
+
+/*
+ * List one sign.
+ */
+    static void
+sign_list_defined(sign_T *sp)
+{
+    char_u	*p;
+
+    smsg((char_u *)"sign %s", sp->sn_name);
+    if (sp->sn_icon != NULL)
+    {
+	MSG_PUTS(" icon=");
+	msg_outtrans(sp->sn_icon);
+# ifdef FEAT_SIGN_ICONS
+	if (sp->sn_image == NULL)
+	    MSG_PUTS(_(" (NOT FOUND)"));
+# else
+	MSG_PUTS(_(" (not supported)"));
+# endif
+    }
+    if (sp->sn_text != NULL)
+    {
+	MSG_PUTS(" text=");
+	msg_outtrans(sp->sn_text);
+    }
+    if (sp->sn_line_hl > 0)
+    {
+	MSG_PUTS(" linehl=");
+	p = get_highlight_name_ext(NULL, sp->sn_line_hl - 1, FALSE);
+	if (p == NULL)
+	    MSG_PUTS("NONE");
+	else
+	    msg_puts(p);
+    }
+    if (sp->sn_text_hl > 0)
+    {
+	MSG_PUTS(" texthl=");
+	p = get_highlight_name_ext(NULL, sp->sn_text_hl - 1, FALSE);
+	if (p == NULL)
+	    MSG_PUTS("NONE");
+	else
+	    msg_puts(p);
+    }
+}
+
+/*
+ * Undefine a sign and free its memory.
+ */
+    static void
+sign_undefine(sign_T *sp, sign_T *sp_prev)
+{
+    vim_free(sp->sn_name);
+    vim_free(sp->sn_icon);
+# ifdef FEAT_SIGN_ICONS
+    if (sp->sn_image != NULL)
+    {
+	out_flush();
+	gui_mch_destroy_sign(sp->sn_image);
+    }
+# endif
+    vim_free(sp->sn_text);
+    if (sp_prev == NULL)
+	first_sign = sp->sn_next;
+    else
+	sp_prev->sn_next = sp->sn_next;
+    vim_free(sp);
+}
+
+/*
+ * Get highlighting attribute for sign "typenr".
+ * If "line" is TRUE: line highl, if FALSE: text highl.
+ */
+    int
+sign_get_attr(int typenr, int line)
+{
+    sign_T	*sp;
+
+    for (sp = first_sign; sp != NULL; sp = sp->sn_next)
+	if (sp->sn_typenr == typenr)
+	{
+	    if (line)
+	    {
+		if (sp->sn_line_hl > 0)
+		    return syn_id2attr(sp->sn_line_hl);
+	    }
+	    else
+	    {
+		if (sp->sn_text_hl > 0)
+		    return syn_id2attr(sp->sn_text_hl);
+	    }
+	    break;
+	}
+    return 0;
+}
+
+/*
+ * Get text mark for sign "typenr".
+ * Returns NULL if there isn't one.
+ */
+    char_u *
+sign_get_text(int typenr)
+{
+    sign_T	*sp;
+
+    for (sp = first_sign; sp != NULL; sp = sp->sn_next)
+	if (sp->sn_typenr == typenr)
+	    return sp->sn_text;
+    return NULL;
+}
+
+# if defined(FEAT_SIGN_ICONS) || defined(PROTO)
+    void *
+sign_get_image(
+    int		typenr)		/* the attribute which may have a sign */
+{
+    sign_T	*sp;
+
+    for (sp = first_sign; sp != NULL; sp = sp->sn_next)
+	if (sp->sn_typenr == typenr)
+	    return sp->sn_image;
+    return NULL;
+}
+# endif
+
+/*
+ * Undefine/free all signs.
+ */
+    void
+free_signs(void)
+{
+    while (first_sign != NULL)
+	sign_undefine(first_sign, NULL);
+}
+
+# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+static enum
+{
+    EXP_SUBCMD,		/* expand :sign sub-commands */
+    EXP_DEFINE,		/* expand :sign define {name} args */
+    EXP_PLACE,		/* expand :sign place {id} args */
+    EXP_UNPLACE,	/* expand :sign unplace" */
+    EXP_SIGN_NAMES	/* expand with name of placed signs */
+} expand_what;
+
+/*
+ * Function given to ExpandGeneric() to obtain the sign command
+ * expansion.
+ */
+    char_u *
+get_sign_name(expand_T *xp UNUSED, int idx)
+{
+    sign_T	*sp;
+    int		current_idx;
+
+    switch (expand_what)
+    {
+    case EXP_SUBCMD:
+	return (char_u *)cmds[idx];
+    case EXP_DEFINE:
+	{
+	    char *define_arg[] =
+	    {
+		"icon=", "linehl=", "text=", "texthl=", NULL
+	    };
+	    return (char_u *)define_arg[idx];
+	}
+    case EXP_PLACE:
+	{
+	    char *place_arg[] =
+	    {
+		"line=", "name=", "group=", "priority=", "file=",
+		"buffer=", NULL
+	    };
+	    return (char_u *)place_arg[idx];
+	}
+    case EXP_UNPLACE:
+	{
+	    char *unplace_arg[] = { "group=", "file=", "buffer=", NULL };
+	    return (char_u *)unplace_arg[idx];
+	}
+    case EXP_SIGN_NAMES:
+	/* Complete with name of signs already defined */
+	current_idx = 0;
+	for (sp = first_sign; sp != NULL; sp = sp->sn_next)
+	    if (current_idx++ == idx)
+		return sp->sn_name;
+	return NULL;
+    default:
+	return NULL;
+    }
+}
+
+/*
+ * Handle command line completion for :sign command.
+ */
+    void
+set_context_in_sign_cmd(expand_T *xp, char_u *arg)
+{
+    char_u	*p;
+    char_u	*end_subcmd;
+    char_u	*last;
+    int		cmd_idx;
+    char_u	*begin_subcmd_args;
+
+    /* Default: expand subcommands. */
+    xp->xp_context = EXPAND_SIGN;
+    expand_what = EXP_SUBCMD;
+    xp->xp_pattern = arg;
+
+    end_subcmd = skiptowhite(arg);
+    if (*end_subcmd == NUL)
+	/* expand subcmd name
+	 * :sign {subcmd}<CTRL-D>*/
+	return;
+
+    cmd_idx = sign_cmd_idx(arg, end_subcmd);
+
+    /* :sign {subcmd} {subcmd_args}
+     *		      |
+     *		      begin_subcmd_args */
+    begin_subcmd_args = skipwhite(end_subcmd);
+    p = skiptowhite(begin_subcmd_args);
+    if (*p == NUL)
+    {
+	/*
+	 * Expand first argument of subcmd when possible.
+	 * For ":jump {id}" and ":unplace {id}", we could
+	 * possibly expand the ids of all signs already placed.
+	 */
+	xp->xp_pattern = begin_subcmd_args;
+	switch (cmd_idx)
+	{
+	    case SIGNCMD_LIST:
+	    case SIGNCMD_UNDEFINE:
+		/* :sign list <CTRL-D>
+		 * :sign undefine <CTRL-D> */
+		expand_what = EXP_SIGN_NAMES;
+		break;
+	    default:
+		xp->xp_context = EXPAND_NOTHING;
+	}
+	return;
+    }
+
+    /* expand last argument of subcmd */
+
+    /* :sign define {name} {args}...
+     *		    |
+     *		    p */
+
+    /* Loop until reaching last argument. */
+    do
+    {
+	p = skipwhite(p);
+	last = p;
+	p = skiptowhite(p);
+    } while (*p != NUL);
+
+    p = vim_strchr(last, '=');
+
+    /* :sign define {name} {args}... {last}=
+     *				     |	   |
+     *				  last	   p */
+    if (p == NULL)
+    {
+	/* Expand last argument name (before equal sign). */
+	xp->xp_pattern = last;
+	switch (cmd_idx)
+	{
+	    case SIGNCMD_DEFINE:
+		expand_what = EXP_DEFINE;
+		break;
+	    case SIGNCMD_PLACE:
+		expand_what = EXP_PLACE;
+		break;
+	    case SIGNCMD_JUMP:
+	    case SIGNCMD_UNPLACE:
+		expand_what = EXP_UNPLACE;
+		break;
+	    default:
+		xp->xp_context = EXPAND_NOTHING;
+	}
+    }
+    else
+    {
+	/* Expand last argument value (after equal sign). */
+	xp->xp_pattern = p + 1;
+	switch (cmd_idx)
+	{
+	    case SIGNCMD_DEFINE:
+		if (STRNCMP(last, "texthl", p - last) == 0 ||
+		    STRNCMP(last, "linehl", p - last) == 0)
+		    xp->xp_context = EXPAND_HIGHLIGHT;
+		else if (STRNCMP(last, "icon", p - last) == 0)
+		    xp->xp_context = EXPAND_FILES;
+		else
+		    xp->xp_context = EXPAND_NOTHING;
+		break;
+	    case SIGNCMD_PLACE:
+		if (STRNCMP(last, "name", p - last) == 0)
+		    expand_what = EXP_SIGN_NAMES;
+		else
+		    xp->xp_context = EXPAND_NOTHING;
+		break;
+	    default:
+		xp->xp_context = EXPAND_NOTHING;
+	}
+    }
+}
+# endif
+
+#endif /* FEAT_SIGNS */
--- a/src/version.c
+++ b/src/version.c
@@ -800,6 +800,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    673,
+/**/
     672,
 /**/
     671,