]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 8.1.0673: functionality for signs is spread out over several files v8.1.0673
authorBram Moolenaar <Bram@vim.org>
Tue, 1 Jan 2019 12:20:31 +0000 (13:20 +0100)
committerBram Moolenaar <Bram@vim.org>
Tue, 1 Jan 2019 12:20:31 +0000 (13:20 +0100)
Problem:    Functionality for signs is spread out over several files.
Solution:   Move most of the sign functionality into sign.c. (Yegappan
            Lakshmanan, closes #3751)

21 files changed:
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 [new file with mode: 0644]
src/sign.c [new file with mode: 0644]
src/version.c

index de0c9b073ea6652f87d34f69a01554a099261a4e..b2b80095e918ed2563805abf830112ca5d329355 100644 (file)
--- 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 \
index 6725c6d7608511677ece688dafab96c9a783459e..a5ee13bd29ab2e13397bc5e18d38f614abb2499e 100644 (file)
@@ -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 \
index 52156dddd4e964ecf8847df62fffb17a596ca665..11ce0fc12f178f725af98401c87a69904e623be7 100644 (file)
@@ -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 \
index c53f182f5f5bf3c40f80beb1d7d45f9c5900468f..2daa8d72bf15fd5fb2252072ee49af77d6bb6ce5 100644 (file)
@@ -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
index c8c1c2f97a35554a51c9f9d5640389ce9ba86f43..784cab931202463858d35af7927e12a531f90725 100644 (file)
@@ -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
index 6995b7662e6b9a72fcb7807c97e5937cb0c78a20..04560d4034ef86a5b1e879b7696106382d8c8caa 100644 (file)
@@ -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
 
index 57c6553cc3403f37691c5b5a0f1ab97ba3336606..70ab5377a33c892dc2fb9bbe77278bc2e859ccb3 100644 (file)
@@ -69,6 +69,7 @@ SRC = arabic.c                                                \
        screen.c                                                \
        search.c                                                \
        sha256.c                                                \
+       sign.c                                                  \
        spell.c                                                 \
        spellfile.c                                             \
        syntax.c                                                \
index 5e22470aff293f4f833f0cc26e5a64d992dbae3a..00c4f24bb60c8cafe1a54f36a102b944eba6d5c4 100644 (file)
@@ -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 @@ $(OUTDIR)/search.obj:     $(OUTDIR) search.c  $(INCL)
 
 $(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 \
index d07fb5556e0f56a4336d64969dcc86205bc2ff46..a16908e9c1af2c80d076dcea8c23ffc979a78489 100644 (file)
@@ -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
index a868da8da649ecc0e2a368379013ed958c9eeb7b..80872ad48b57e34024721c17903b9e4555b12218 100644 (file)
@@ -302,7 +302,7 @@ ALL_LIBS = $(LIBS) $(GUI_LIB_DIR) $(GUI_LIB) \
 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 buffer.obj charset.obj crypt.obj crypt_
        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]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
+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 \
index 38bb1090da72ceedbefa538711b4e49d9ea97366..7e2a843de5b11c92c194a3683459194deffdbc49 100644 (file)
@@ -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 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/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 \
index e134306015fc4a9f00e967cbc5850eee9506ab4b..6e7094cec0909dfb44dc7a9a1ec3d69b942a3d5f 100644 (file)
@@ -35,6 +35,7 @@ Most code can be found in a file with an obvious name (incomplete list):
        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
index 07b89e320746e8f889f6f0f5ca7c4b754081b525..b3bd2aa56be4ef36872d05e245c8fca35b9578c7 100644 (file)
@@ -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.
  */
index 2e9b16a3e3edd38171e68ad395182cce9f4d9aac..97921e7c04e1d37515fe73ecddd9fdc38a251392 100644 (file)
@@ -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.
  */
index 208f2b5766ce6e686f77dc8f983606bae45c34ce..52c0e5bedd63964e0dd2facefa9419779d757e42 100644 (file)
@@ -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.
  */
index 92d9714697aa34afb5766bb705ca40fcddd24f17..cbd446015c12ab1fd9fee6f68b5d0b2d46c55ec3 100644 (file)
@@ -172,6 +172,9 @@ void qsort(void *base, size_t elm_count, size_t elm_size, int (*cmp)(const void
 #  include "sha256.pro"
 # endif
 # include "search.pro"
+# ifdef FEAT_SIGNS
+# include "sign.pro"
+# endif
 # include "spell.pro"
 # include "spellfile.pro"
 # include "syntax.pro"
index ecc830188c110c4722dd780abffd1ea5949f6e25..91494db64d246eaeff5846b95c529195253c81f6 100644 (file)
@@ -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);
index 0b9d687c94578bab806b1d3354713e27cb2739ef..c769b4b6a37cc0cf92f3c23bcdeb629c1fadf6bf 100644 (file)
@@ -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);
diff --git a/src/proto/sign.pro b/src/proto/sign.pro
new file mode 100644 (file)
index 0000000..6470f52
--- /dev/null
@@ -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);
diff --git a/src/sign.c b/src/sign.c
new file mode 100644 (file)
index 0000000..e600bfc
--- /dev/null
@@ -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 */
index 623d2a0ef55ad0e180fdff689715c32174d12243..824091224e363e0c3e29b6d0fb283986dc612ea2 100644 (file)
@@ -799,6 +799,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    673,
 /**/
     672,
 /**/