Mercurial > vim
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 */ |