comparison src/ex_cmds.c @ 15209:3a99b2e6d136 v8.1.0614

patch 8.1.0614: placing signs can be complicated commit https://github.com/vim/vim/commit/162b71479bd4dcdb3a2ef9198a1444f6f99e6843 Author: Bram Moolenaar <Bram@vim.org> Date: Fri Dec 21 15:17:36 2018 +0100 patch 8.1.0614: placing signs can be complicated Problem: Placing signs can be complicated. Solution: Add functions for defining and placing signs. Introduce a group name to avoid different plugins using the same signs. (Yegappan Lakshmanan, closes #3652)
author Bram Moolenaar <Bram@vim.org>
date Fri, 21 Dec 2018 15:30:07 +0100
parents b63787182765
children de63593896b3
comparison
equal deleted inserted replaced
15208:acf68008ca43 15209:3a99b2e6d136
7642 *end_cmd = save; 7642 *end_cmd = save;
7643 return idx; 7643 return idx;
7644 } 7644 }
7645 7645
7646 /* 7646 /*
7647 * Find a sign by name. Also returns pointer to the previous sign.
7648 */
7649 static sign_T *
7650 sign_find(char_u *name, sign_T **sp_prev)
7651 {
7652 sign_T *sp;
7653
7654 if (sp_prev != NULL)
7655 *sp_prev = NULL;
7656 for (sp = first_sign; sp != NULL; sp = sp->sn_next)
7657 {
7658 if (STRCMP(sp->sn_name, name) == 0)
7659 break;
7660 if (sp_prev != NULL)
7661 *sp_prev = sp;
7662 }
7663
7664 return sp;
7665 }
7666
7667 /*
7668 * Define a new sign or update an existing sign
7669 */
7670 int
7671 sign_define_by_name(
7672 char_u *name,
7673 char_u *icon,
7674 char_u *linehl,
7675 char_u *text,
7676 char_u *texthl)
7677 {
7678 sign_T *sp_prev;
7679 sign_T *sp;
7680
7681 sp = sign_find(name, &sp_prev);
7682 if (sp == NULL)
7683 {
7684 sign_T *lp;
7685 int start = next_sign_typenr;
7686
7687 // Allocate a new sign.
7688 sp = (sign_T *)alloc_clear_id((unsigned)sizeof(sign_T),
7689 aid_sign_define_by_name);
7690 if (sp == NULL)
7691 return FAIL;
7692
7693 // Check that next_sign_typenr is not already being used.
7694 // This only happens after wrapping around. Hopefully
7695 // another one got deleted and we can use its number.
7696 for (lp = first_sign; lp != NULL; )
7697 {
7698 if (lp->sn_typenr == next_sign_typenr)
7699 {
7700 ++next_sign_typenr;
7701 if (next_sign_typenr == MAX_TYPENR)
7702 next_sign_typenr = 1;
7703 if (next_sign_typenr == start)
7704 {
7705 vim_free(sp);
7706 EMSG(_("E612: Too many signs defined"));
7707 return FAIL;
7708 }
7709 lp = first_sign; // start all over
7710 continue;
7711 }
7712 lp = lp->sn_next;
7713 }
7714
7715 sp->sn_typenr = next_sign_typenr;
7716 if (++next_sign_typenr == MAX_TYPENR)
7717 next_sign_typenr = 1; // wrap around
7718
7719 sp->sn_name = vim_strsave(name);
7720 if (sp->sn_name == NULL) // out of memory
7721 {
7722 vim_free(sp);
7723 return FAIL;
7724 }
7725
7726 // add the new sign to the list of signs
7727 if (sp_prev == NULL)
7728 first_sign = sp;
7729 else
7730 sp_prev->sn_next = sp;
7731 }
7732
7733 // set values for a defined sign.
7734 if (icon != NULL)
7735 {
7736 vim_free(sp->sn_icon);
7737 sp->sn_icon = vim_strsave(icon);
7738 backslash_halve(sp->sn_icon);
7739 # ifdef FEAT_SIGN_ICONS
7740 if (gui.in_use)
7741 {
7742 out_flush();
7743 if (sp->sn_image != NULL)
7744 gui_mch_destroy_sign(sp->sn_image);
7745 sp->sn_image = gui_mch_register_sign(sp->sn_icon);
7746 }
7747 # endif
7748 }
7749
7750 if (text != NULL)
7751 {
7752 char_u *s;
7753 char_u *endp;
7754 int cells;
7755 int len;
7756
7757 endp = text + (int)STRLEN(text);
7758 for (s = text; s + 1 < endp; ++s)
7759 if (*s == '\\')
7760 {
7761 // Remove a backslash, so that it is possible
7762 // to use a space.
7763 STRMOVE(s, s + 1);
7764 --endp;
7765 }
7766 # ifdef FEAT_MBYTE
7767 // Count cells and check for non-printable chars
7768 if (has_mbyte)
7769 {
7770 cells = 0;
7771 for (s = text; s < endp; s += (*mb_ptr2len)(s))
7772 {
7773 if (!vim_isprintc((*mb_ptr2char)(s)))
7774 break;
7775 cells += (*mb_ptr2cells)(s);
7776 }
7777 }
7778 else
7779 # endif
7780 {
7781 for (s = text; s < endp; ++s)
7782 if (!vim_isprintc(*s))
7783 break;
7784 cells = (int)(s - text);
7785 }
7786 // Currently must be one or two display cells
7787 if (s != endp || cells < 1 || cells > 2)
7788 {
7789 EMSG2(_("E239: Invalid sign text: %s"), text);
7790 return FAIL;
7791 }
7792
7793 vim_free(sp->sn_text);
7794 // Allocate one byte more if we need to pad up
7795 // with a space.
7796 len = (int)(endp - text + ((cells == 1) ? 1 : 0));
7797 sp->sn_text = vim_strnsave(text, len);
7798
7799 if (sp->sn_text != NULL && cells == 1)
7800 STRCPY(sp->sn_text + len - 1, " ");
7801 }
7802
7803 if (linehl != NULL)
7804 sp->sn_line_hl = syn_check_group(linehl, (int)STRLEN(linehl));
7805
7806 if (texthl != NULL)
7807 sp->sn_text_hl = syn_check_group(texthl, (int)STRLEN(texthl));
7808
7809 return OK;
7810 }
7811
7812 /*
7813 * Free the sign specified by 'name'.
7814 */
7815 int
7816 sign_undefine_by_name(char_u *name)
7817 {
7818 sign_T *sp_prev;
7819 sign_T *sp;
7820
7821 sp = sign_find(name, &sp_prev);
7822 if (sp == NULL)
7823 {
7824 EMSG2(_("E155: Unknown sign: %s"), name);
7825 return FAIL;
7826 }
7827 sign_undefine(sp, sp_prev);
7828
7829 return OK;
7830 }
7831
7832 /*
7833 * List the signs matching 'name'
7834 */
7835 static void
7836 sign_list_by_name(char_u *name)
7837 {
7838 sign_T *sp;
7839
7840 sp = sign_find(name, NULL);
7841 if (sp != NULL)
7842 sign_list_defined(sp);
7843 else
7844 EMSG2(_("E155: Unknown sign: %s"), name);
7845 }
7846
7847 /*
7848 * Place a sign at the specifed file location or update a sign.
7849 */
7850 int
7851 sign_place(
7852 int *sign_id,
7853 char_u *sign_group,
7854 char_u *sign_name,
7855 buf_T *buf,
7856 linenr_T lnum,
7857 int prio)
7858 {
7859 sign_T *sp;
7860
7861 // Check for reserved character '*' in group name
7862 if (sign_group != NULL && (*sign_group == '*' || *sign_group == '\0'))
7863 return FAIL;
7864
7865 for (sp = first_sign; sp != NULL; sp = sp->sn_next)
7866 if (STRCMP(sp->sn_name, sign_name) == 0)
7867 break;
7868 if (sp == NULL)
7869 {
7870 EMSG2(_("E155: Unknown sign: %s"), sign_name);
7871 return FAIL;
7872 }
7873 if (*sign_id == 0)
7874 {
7875 // Allocate a new sign id
7876 int id = 1;
7877 signlist_T *sign;
7878
7879 while ((sign = buf_getsign_with_id(buf, id, sign_group)) != NULL)
7880 id++;
7881
7882 *sign_id = id;
7883 }
7884
7885 if (lnum > 0)
7886 // ":sign place {id} line={lnum} name={name} file={fname}":
7887 // place a sign
7888 buf_addsign(buf, *sign_id, sign_group, prio, lnum, sp->sn_typenr);
7889 else
7890 // ":sign place {id} file={fname}": change sign type
7891 lnum = buf_change_sign_type(buf, *sign_id, sign_group, sp->sn_typenr);
7892 if (lnum > 0)
7893 update_debug_sign(buf, lnum);
7894 else
7895 {
7896 EMSG2(_("E885: Not possible to change sign %s"), sign_name);
7897 return FAIL;
7898 }
7899
7900 return OK;
7901 }
7902
7903 /*
7904 * Unplace the specified sign
7905 */
7906 int
7907 sign_unplace(int sign_id, char_u *sign_group, buf_T *buf)
7908 {
7909 if (sign_id == 0)
7910 {
7911 // Delete all the signs in the specified buffer
7912 redraw_buf_later(buf, NOT_VALID);
7913 buf_delete_signs(buf, sign_group);
7914 }
7915 else
7916 {
7917 linenr_T lnum;
7918
7919 // Delete only the specified signs
7920 lnum = buf_delsign(buf, sign_id, sign_group);
7921 if (lnum == 0)
7922 return FAIL;
7923 update_debug_sign(buf, lnum);
7924 }
7925
7926 return OK;
7927 }
7928
7929 /*
7647 * ":sign" command 7930 * ":sign" command
7648 */ 7931 */
7649 void 7932 void
7650 ex_sign(exarg_T *eap) 7933 ex_sign(exarg_T *eap)
7651 { 7934 {
7652 char_u *arg = eap->arg; 7935 char_u *arg = eap->arg;
7653 char_u *p; 7936 char_u *p;
7654 int idx; 7937 int idx;
7655 sign_T *sp; 7938 sign_T *sp;
7656 sign_T *sp_prev;
7657 buf_T *buf = NULL; 7939 buf_T *buf = NULL;
7658 7940
7659 /* Parse the subcommand. */ 7941 /* Parse the subcommand. */
7660 p = skiptowhite(arg); 7942 p = skiptowhite(arg);
7661 idx = sign_cmd_idx(arg, p); 7943 idx = sign_cmd_idx(arg, p);
7679 } 7961 }
7680 else if (*arg == NUL) 7962 else if (*arg == NUL)
7681 EMSG(_("E156: Missing sign name")); 7963 EMSG(_("E156: Missing sign name"));
7682 else 7964 else
7683 { 7965 {
7966 char_u *name;
7967 char_u *icon = NULL;
7968 char_u *text = NULL;
7969 char_u *linehl = NULL;
7970 char_u *texthl = NULL;
7971
7684 /* Isolate the sign name. If it's a number skip leading zeroes, 7972 /* Isolate the sign name. If it's a number skip leading zeroes,
7685 * so that "099" and "99" are the same sign. But keep "0". */ 7973 * so that "099" and "99" are the same sign. But keep "0". */
7686 p = skiptowhite(arg); 7974 p = skiptowhite(arg);
7687 if (*p != NUL) 7975 if (*p != NUL)
7688 *p++ = NUL; 7976 *p++ = NUL;
7689 while (arg[0] == '0' && arg[1] != NUL) 7977 while (arg[0] == '0' && arg[1] != NUL)
7690 ++arg; 7978 ++arg;
7691 7979 name = vim_strsave(arg);
7692 sp_prev = NULL; 7980
7693 for (sp = first_sign; sp != NULL; sp = sp->sn_next)
7694 {
7695 if (STRCMP(sp->sn_name, arg) == 0)
7696 break;
7697 sp_prev = sp;
7698 }
7699 if (idx == SIGNCMD_DEFINE) 7981 if (idx == SIGNCMD_DEFINE)
7700 { 7982 {
7983 int failed = FALSE;
7984
7701 /* ":sign define {name} ...": define a sign */ 7985 /* ":sign define {name} ...": define a sign */
7702 if (sp == NULL)
7703 {
7704 sign_T *lp;
7705 int start = next_sign_typenr;
7706
7707 /* Allocate a new sign. */
7708 sp = (sign_T *)alloc_clear((unsigned)sizeof(sign_T));
7709 if (sp == NULL)
7710 return;
7711
7712 /* Check that next_sign_typenr is not already being used.
7713 * This only happens after wrapping around. Hopefully
7714 * another one got deleted and we can use its number. */
7715 for (lp = first_sign; lp != NULL; )
7716 {
7717 if (lp->sn_typenr == next_sign_typenr)
7718 {
7719 ++next_sign_typenr;
7720 if (next_sign_typenr == MAX_TYPENR)
7721 next_sign_typenr = 1;
7722 if (next_sign_typenr == start)
7723 {
7724 vim_free(sp);
7725 EMSG(_("E612: Too many signs defined"));
7726 return;
7727 }
7728 lp = first_sign; /* start all over */
7729 continue;
7730 }
7731 lp = lp->sn_next;
7732 }
7733
7734 sp->sn_typenr = next_sign_typenr;
7735 if (++next_sign_typenr == MAX_TYPENR)
7736 next_sign_typenr = 1; /* wrap around */
7737
7738 sp->sn_name = vim_strsave(arg);
7739 if (sp->sn_name == NULL) /* out of memory */
7740 {
7741 vim_free(sp);
7742 return;
7743 }
7744
7745 /* add the new sign to the list of signs */
7746 if (sp_prev == NULL)
7747 first_sign = sp;
7748 else
7749 sp_prev->sn_next = sp;
7750 }
7751 7986
7752 /* set values for a defined sign. */ 7987 /* set values for a defined sign. */
7753 for (;;) 7988 for (;;)
7754 { 7989 {
7755 arg = skipwhite(p); 7990 arg = skipwhite(p);
7757 break; 7992 break;
7758 p = skiptowhite_esc(arg); 7993 p = skiptowhite_esc(arg);
7759 if (STRNCMP(arg, "icon=", 5) == 0) 7994 if (STRNCMP(arg, "icon=", 5) == 0)
7760 { 7995 {
7761 arg += 5; 7996 arg += 5;
7762 vim_free(sp->sn_icon); 7997 icon = vim_strnsave(arg, (int)(p - arg));
7763 sp->sn_icon = vim_strnsave(arg, (int)(p - arg));
7764 backslash_halve(sp->sn_icon);
7765 # ifdef FEAT_SIGN_ICONS
7766 if (gui.in_use)
7767 {
7768 out_flush();
7769 if (sp->sn_image != NULL)
7770 gui_mch_destroy_sign(sp->sn_image);
7771 sp->sn_image = gui_mch_register_sign(sp->sn_icon);
7772 }
7773 # endif
7774 } 7998 }
7775 else if (STRNCMP(arg, "text=", 5) == 0) 7999 else if (STRNCMP(arg, "text=", 5) == 0)
7776 { 8000 {
7777 char_u *s;
7778 int cells;
7779 int len;
7780
7781 arg += 5; 8001 arg += 5;
7782 for (s = arg; s + 1 < p; ++s) 8002 text = vim_strnsave(arg, (int)(p - arg));
7783 if (*s == '\\')
7784 {
7785 // Remove a backslash, so that it is possible
7786 // to use a space.
7787 STRMOVE(s, s + 1);
7788 --p;
7789 }
7790 # ifdef FEAT_MBYTE
7791 /* Count cells and check for non-printable chars */
7792 if (has_mbyte)
7793 {
7794 cells = 0;
7795 for (s = arg; s < p; s += (*mb_ptr2len)(s))
7796 {
7797 if (!vim_isprintc((*mb_ptr2char)(s)))
7798 break;
7799 cells += (*mb_ptr2cells)(s);
7800 }
7801 }
7802 else
7803 # endif
7804 {
7805 for (s = arg; s < p; ++s)
7806 if (!vim_isprintc(*s))
7807 break;
7808 cells = (int)(s - arg);
7809 }
7810 /* Currently must be one or two display cells */
7811 if (s != p || cells < 1 || cells > 2)
7812 {
7813 *p = NUL;
7814 EMSG2(_("E239: Invalid sign text: %s"), arg);
7815 return;
7816 }
7817
7818 vim_free(sp->sn_text);
7819 /* Allocate one byte more if we need to pad up
7820 * with a space. */
7821 len = (int)(p - arg + ((cells == 1) ? 1 : 0));
7822 sp->sn_text = vim_strnsave(arg, len);
7823
7824 if (sp->sn_text != NULL && cells == 1)
7825 STRCPY(sp->sn_text + len - 1, " ");
7826 } 8003 }
7827 else if (STRNCMP(arg, "linehl=", 7) == 0) 8004 else if (STRNCMP(arg, "linehl=", 7) == 0)
7828 { 8005 {
7829 arg += 7; 8006 arg += 7;
7830 sp->sn_line_hl = syn_check_group(arg, (int)(p - arg)); 8007 linehl = vim_strnsave(arg, (int)(p - arg));
7831 } 8008 }
7832 else if (STRNCMP(arg, "texthl=", 7) == 0) 8009 else if (STRNCMP(arg, "texthl=", 7) == 0)
7833 { 8010 {
7834 arg += 7; 8011 arg += 7;
7835 sp->sn_text_hl = syn_check_group(arg, (int)(p - arg)); 8012 texthl = vim_strnsave(arg, (int)(p - arg));
7836 } 8013 }
7837 else 8014 else
7838 { 8015 {
7839 EMSG2(_(e_invarg2), arg); 8016 EMSG2(_(e_invarg2), arg);
7840 return; 8017 failed = TRUE;
8018 break;
7841 } 8019 }
7842 } 8020 }
7843 } 8021
7844 else if (sp == NULL) 8022 if (!failed)
7845 EMSG2(_("E155: Unknown sign: %s"), arg); 8023 sign_define_by_name(name, icon, linehl, text, texthl);
8024
8025 vim_free(icon);
8026 vim_free(text);
8027 vim_free(linehl);
8028 vim_free(texthl);
8029 }
7846 else if (idx == SIGNCMD_LIST) 8030 else if (idx == SIGNCMD_LIST)
7847 /* ":sign list {name}" */ 8031 /* ":sign list {name}" */
7848 sign_list_defined(sp); 8032 sign_list_by_name(name);
7849 else 8033 else
7850 /* ":sign undefine {name}" */ 8034 /* ":sign undefine {name}" */
7851 sign_undefine(sp, sp_prev); 8035 sign_undefine_by_name(name);
8036
8037 vim_free(name);
8038 return;
7852 } 8039 }
7853 } 8040 }
7854 else 8041 else
7855 { 8042 {
7856 int id = -1; 8043 int id = -1;
7857 linenr_T lnum = -1; 8044 linenr_T lnum = -1;
7858 char_u *sign_name = NULL; 8045 char_u *sign_name = NULL;
8046 char_u *group = NULL;
8047 int prio = SIGN_DEF_PRIO;
7859 char_u *arg1; 8048 char_u *arg1;
8049 int bufarg = FALSE;
7860 8050
7861 if (*arg == NUL) 8051 if (*arg == NUL)
7862 { 8052 {
7863 if (idx == SIGNCMD_PLACE) 8053 if (idx == SIGNCMD_PLACE)
7864 { 8054 {
7865 /* ":sign place": list placed signs in all buffers */ 8055 /* ":sign place": list placed signs in all buffers */
7866 sign_list_placed(NULL); 8056 sign_list_placed(NULL, NULL);
7867 } 8057 }
7868 else if (idx == SIGNCMD_UNPLACE) 8058 else if (idx == SIGNCMD_UNPLACE)
7869 { 8059 {
7870 /* ":sign unplace": remove placed sign at cursor */ 8060 /* ":sign unplace": remove placed sign at cursor */
7871 id = buf_findsign_id(curwin->w_buffer, curwin->w_cursor.lnum); 8061 id = buf_findsign_id(curwin->w_buffer, curwin->w_cursor.lnum);
7872 if (id > 0) 8062 if (id > 0)
7873 { 8063 sign_unplace(id, NULL, curwin->w_buffer);
7874 buf_delsign(curwin->w_buffer, id);
7875 update_debug_sign(curwin->w_buffer, curwin->w_cursor.lnum);
7876 }
7877 else 8064 else
7878 EMSG(_("E159: Missing sign number")); 8065 EMSG(_("E159: Missing sign number"));
7879 } 8066 }
7880 else 8067 else
7881 EMSG(_(e_argreq)); 8068 EMSG(_(e_argreq));
7904 arg = skipwhite(arg); 8091 arg = skipwhite(arg);
7905 if (idx == SIGNCMD_UNPLACE && *arg == NUL) 8092 if (idx == SIGNCMD_UNPLACE && *arg == NUL)
7906 { 8093 {
7907 /* ":sign unplace {id}": remove placed sign by number */ 8094 /* ":sign unplace {id}": remove placed sign by number */
7908 FOR_ALL_BUFFERS(buf) 8095 FOR_ALL_BUFFERS(buf)
7909 if ((lnum = buf_delsign(buf, id)) != 0) 8096 sign_unplace(id, NULL, buf);
7910 update_debug_sign(buf, lnum);
7911 return; 8097 return;
7912 } 8098 }
7913 } 8099 }
7914 } 8100 }
7915 8101
7916 /* 8102 /*
7917 * Check for line={lnum} name={name} and file={fname} or buffer={nr}. 8103 * Check for line={lnum} name={name} group={group} priority={prio}
7918 * Leave "arg" pointing to {fname}. 8104 * and file={fname} or buffer={nr}. Leave "arg" pointing to {fname}.
7919 */ 8105 */
7920 for (;;) 8106 while (*arg != NUL)
7921 { 8107 {
7922 if (STRNCMP(arg, "line=", 5) == 0) 8108 if (STRNCMP(arg, "line=", 5) == 0)
7923 { 8109 {
7924 arg += 5; 8110 arg += 5;
7925 lnum = atoi((char *)arg); 8111 lnum = atoi((char *)arg);
7943 if (*arg != NUL) 8129 if (*arg != NUL)
7944 *arg++ = NUL; 8130 *arg++ = NUL;
7945 while (sign_name[0] == '0' && sign_name[1] != NUL) 8131 while (sign_name[0] == '0' && sign_name[1] != NUL)
7946 ++sign_name; 8132 ++sign_name;
7947 } 8133 }
8134 else if (STRNCMP(arg, "group=", 6) == 0)
8135 {
8136 arg += 6;
8137 group = arg;
8138 arg = skiptowhite(arg);
8139 if (*arg != NUL)
8140 *arg++ = NUL;
8141 }
8142 else if (STRNCMP(arg, "priority=", 9) == 0)
8143 {
8144 arg += 9;
8145 prio = atoi((char *)arg);
8146 arg = skiptowhite(arg);
8147 }
7948 else if (STRNCMP(arg, "file=", 5) == 0) 8148 else if (STRNCMP(arg, "file=", 5) == 0)
7949 { 8149 {
7950 arg += 5; 8150 arg += 5;
7951 buf = buflist_findname(arg); 8151 buf = buflist_findname_exp(arg);
8152 bufarg = TRUE;
7952 break; 8153 break;
7953 } 8154 }
7954 else if (STRNCMP(arg, "buffer=", 7) == 0) 8155 else if (STRNCMP(arg, "buffer=", 7) == 0)
7955 { 8156 {
7956 arg += 7; 8157 arg += 7;
7957 buf = buflist_findnr((int)getdigits(&arg)); 8158 buf = buflist_findnr((int)getdigits(&arg));
7958 if (*skipwhite(arg) != NUL) 8159 if (*skipwhite(arg) != NUL)
7959 EMSG(_(e_trailing)); 8160 EMSG(_(e_trailing));
8161 bufarg = TRUE;
7960 break; 8162 break;
7961 } 8163 }
7962 else 8164 else
7963 { 8165 {
7964 EMSG(_(e_invarg)); 8166 EMSG(_(e_invarg));
7965 return; 8167 return;
7966 } 8168 }
7967 arg = skipwhite(arg); 8169 arg = skipwhite(arg);
7968 } 8170 }
7969 8171
7970 if (buf == NULL) 8172 if ((!bufarg && group == NULL) || (group != NULL && *group == '\0'))
8173 {
8174 // File or buffer is not specified or an empty group is used
8175 EMSG(_(e_invarg));
8176 return;
8177 }
8178
8179 if (bufarg && buf == NULL)
7971 { 8180 {
7972 EMSG2(_("E158: Invalid buffer name: %s"), arg); 8181 EMSG2(_("E158: Invalid buffer name: %s"), arg);
7973 } 8182 }
7974 else if (id <= 0 && !(idx == SIGNCMD_UNPLACE && id == -2)) 8183 else if (id <= 0 && !(idx == SIGNCMD_UNPLACE && id == -2))
7975 { 8184 {
7976 if (lnum >= 0 || sign_name != NULL) 8185 if ((group == NULL) && (lnum >= 0 || sign_name != NULL))
7977 EMSG(_(e_invarg)); 8186 EMSG(_(e_invarg));
7978 else 8187 else
7979 /* ":sign place file={fname}": list placed signs in one file */ 8188 // ":sign place file={fname}": list placed signs in one file
7980 sign_list_placed(buf); 8189 // ":sign place group={group} file={fname}"
8190 // ":sign place group=* file={fname}"
8191 sign_list_placed(buf, group);
7981 } 8192 }
7982 else if (idx == SIGNCMD_JUMP) 8193 else if (idx == SIGNCMD_JUMP)
7983 { 8194 {
7984 /* ":sign jump {id} file={fname}" */ 8195 /* ":sign jump {id} file={fname}" */
7985 if (lnum >= 0 || sign_name != NULL) 8196 if (lnum >= 0 || sign_name != NULL)
7986 EMSG(_(e_invarg)); 8197 EMSG(_(e_invarg));
7987 else if ((lnum = buf_findsign(buf, id)) > 0) 8198 else if ((lnum = buf_findsign(buf, id, group)) > 0)
7988 { /* goto a sign ... */ 8199 { /* goto a sign ... */
7989 if (buf_jump_open_win(buf) != NULL) 8200 if (buf_jump_open_win(buf) != NULL)
7990 { /* ... in a current window */ 8201 { /* ... in a current window */
7991 curwin->w_cursor.lnum = lnum; 8202 curwin->w_cursor.lnum = lnum;
7992 check_cursor_lnum(); 8203 check_cursor_lnum();
8019 { 8230 {
8020 if (lnum >= 0 || sign_name != NULL) 8231 if (lnum >= 0 || sign_name != NULL)
8021 EMSG(_(e_invarg)); 8232 EMSG(_(e_invarg));
8022 else if (id == -2) 8233 else if (id == -2)
8023 { 8234 {
8024 /* ":sign unplace * file={fname}" */ 8235 if (buf != NULL)
8025 redraw_buf_later(buf, NOT_VALID); 8236 // ":sign unplace * file={fname}"
8026 buf_delete_signs(buf); 8237 sign_unplace(0, group, buf);
8238 else
8239 // ":sign unplace * group=*": remove all placed signs
8240 FOR_ALL_BUFFERS(buf)
8241 if (buf->b_signlist != NULL)
8242 buf_delete_signs(buf, group);
8027 } 8243 }
8028 else 8244 else
8029 { 8245 {
8030 /* ":sign unplace {id} file={fname}" */ 8246 if (buf != NULL)
8031 lnum = buf_delsign(buf, id); 8247 // ":sign unplace {id} file={fname}"
8032 update_debug_sign(buf, lnum); 8248 // ":sign unplace {id} group={group} file={fname}"
8249 // ":sign unplace {id} group=* file={fname}"
8250 sign_unplace(id, group, buf);
8251 else
8252 // ":sign unplace {id} group={group}":
8253 // ":sign unplace {id} group=*":
8254 // remove all placed signs in this group.
8255 FOR_ALL_BUFFERS(buf)
8256 if (buf->b_signlist != NULL)
8257 sign_unplace(id, group, buf);
8033 } 8258 }
8034 } 8259 }
8035 /* idx == SIGNCMD_PLACE */ 8260 /* idx == SIGNCMD_PLACE */
8036 else if (sign_name != NULL) 8261 else if (sign_name != NULL && buf != NULL)
8037 { 8262 sign_place(&id, group, sign_name, buf, lnum, prio);
8038 for (sp = first_sign; sp != NULL; sp = sp->sn_next)
8039 if (STRCMP(sp->sn_name, sign_name) == 0)
8040 break;
8041 if (sp == NULL)
8042 {
8043 EMSG2(_("E155: Unknown sign: %s"), sign_name);
8044 return;
8045 }
8046 if (lnum > 0)
8047 /* ":sign place {id} line={lnum} name={name} file={fname}":
8048 * place a sign */
8049 buf_addsign(buf, id, lnum, sp->sn_typenr);
8050 else
8051 /* ":sign place {id} file={fname}": change sign type */
8052 lnum = buf_change_sign_type(buf, id, sp->sn_typenr);
8053 if (lnum > 0)
8054 update_debug_sign(buf, lnum);
8055 else
8056 EMSG2(_("E885: Not possible to change sign %s"), sign_name);
8057 }
8058 else 8263 else
8059 EMSG(_(e_invarg)); 8264 EMSG(_(e_invarg));
8265 }
8266 }
8267
8268 /*
8269 * Return information about a specified sign
8270 */
8271 static void
8272 sign_getinfo(sign_T *sp, dict_T *retdict)
8273 {
8274 char_u *p;
8275
8276 dict_add_string(retdict, "name", (char_u *)sp->sn_name);
8277 if (sp->sn_icon != NULL)
8278 dict_add_string(retdict, "icon", (char_u *)sp->sn_icon);
8279 if (sp->sn_text != NULL)
8280 dict_add_string(retdict, "text", (char_u *)sp->sn_text);
8281 if (sp->sn_line_hl > 0)
8282 {
8283 p = get_highlight_name_ext(NULL, sp->sn_line_hl - 1, FALSE);
8284 if (p == NULL)
8285 p = (char_u *)"NONE";
8286 dict_add_string(retdict, "linehl", (char_u *)p);
8287 }
8288 if (sp->sn_text_hl > 0)
8289 {
8290 p = get_highlight_name_ext(NULL, sp->sn_text_hl - 1, FALSE);
8291 if (p == NULL)
8292 p = (char_u *)"NONE";
8293 dict_add_string(retdict, "texthl", (char_u *)p);
8294 }
8295 }
8296
8297 /*
8298 * If 'name' is NULL, return a list of all the defined signs.
8299 * Otherwise, return information about the specified sign.
8300 */
8301 void
8302 sign_getlist(char_u *name, list_T *retlist)
8303 {
8304 sign_T *sp = first_sign;
8305 dict_T *dict;
8306
8307 if (name != NULL)
8308 {
8309 sp = sign_find(name, NULL);
8310 if (sp == NULL)
8311 return;
8312 }
8313
8314 for (; sp != NULL && !got_int; sp = sp->sn_next)
8315 {
8316 if ((dict = dict_alloc_id(aid_sign_getlist)) == NULL)
8317 return;
8318 if (list_append_dict(retlist, dict) == FAIL)
8319 return;
8320 sign_getinfo(sp, dict);
8321
8322 if (name != NULL) // handle only the specified sign
8323 break;
8324 }
8325 }
8326
8327 /*
8328 * Return information about all the signs placed in a buffer
8329 */
8330 static void
8331 sign_get_placed_in_buf(
8332 buf_T *buf,
8333 linenr_T lnum,
8334 int sign_id,
8335 char_u *sign_group,
8336 list_T *retlist)
8337 {
8338 dict_T *d;
8339 list_T *l;
8340 signlist_T *sign;
8341 dict_T *sdict;
8342
8343 if ((d = dict_alloc_id(aid_sign_getplaced_dict)) == NULL)
8344 return;
8345 list_append_dict(retlist, d);
8346
8347 dict_add_number(d, "bufnr", (long)buf->b_fnum);
8348
8349 if ((l = list_alloc_id(aid_sign_getplaced_list)) == NULL)
8350 return;
8351 dict_add_list(d, "signs", l);
8352
8353 FOR_ALL_SIGNS_IN_BUF(buf)
8354 {
8355 if (!sign_in_group(sign, sign_group))
8356 continue;
8357 if ((lnum == 0 && sign_id == 0) ||
8358 (sign_id == 0 && lnum == sign->lnum) ||
8359 (lnum == 0 && sign_id == sign->id) ||
8360 (lnum == sign->lnum && sign_id == sign->id))
8361 {
8362 if ((sdict = sign_get_info(sign)) != NULL)
8363 list_append_dict(l, sdict);
8364 }
8365 }
8366 }
8367
8368 /*
8369 * Get a list of signs placed in buffer 'buf'. If 'num' is non-zero, return the
8370 * sign placed at the line number. If 'lnum' is zero, return all the signs
8371 * placed in 'buf'. If 'buf' is NULL, return signs placed in all the buffers.
8372 */
8373 void
8374 sign_get_placed(
8375 buf_T *buf,
8376 linenr_T lnum,
8377 int sign_id,
8378 char_u *sign_group,
8379 list_T *retlist)
8380 {
8381 if (buf != NULL)
8382 sign_get_placed_in_buf(buf, lnum, sign_id, sign_group, retlist);
8383 else
8384 {
8385 FOR_ALL_BUFFERS(buf)
8386 {
8387 if (buf->b_signlist != NULL)
8388 sign_get_placed_in_buf(buf, 0, sign_id, sign_group, retlist);
8389 }
8060 } 8390 }
8061 } 8391 }
8062 8392
8063 # if defined(FEAT_SIGN_ICONS) || defined(PROTO) 8393 # if defined(FEAT_SIGN_ICONS) || defined(PROTO)
8064 /* 8394 /*
8212 if (sp->sn_typenr == typenr) 8542 if (sp->sn_typenr == typenr)
8213 return sp->sn_name; 8543 return sp->sn_name;
8214 return (char_u *)_("[Deleted]"); 8544 return (char_u *)_("[Deleted]");
8215 } 8545 }
8216 8546
8217 # if defined(EXITFREE) || defined(PROTO)
8218 /* 8547 /*
8219 * Undefine/free all signs. 8548 * Undefine/free all signs.
8220 */ 8549 */
8221 void 8550 void
8222 free_signs(void) 8551 free_signs(void)
8223 { 8552 {
8224 while (first_sign != NULL) 8553 while (first_sign != NULL)
8225 sign_undefine(first_sign, NULL); 8554 sign_undefine(first_sign, NULL);
8226 } 8555 }
8227 # endif
8228 8556
8229 # if defined(FEAT_CMDL_COMPL) || defined(PROTO) 8557 # if defined(FEAT_CMDL_COMPL) || defined(PROTO)
8230 static enum 8558 static enum
8231 { 8559 {
8232 EXP_SUBCMD, /* expand :sign sub-commands */ 8560 EXP_SUBCMD, /* expand :sign sub-commands */