Mercurial > vim
comparison src/ex_cmds.c @ 15330:a6330a49e036 v8.1.0673
patch 8.1.0673: functionality for signs is spread out over several files
commit https://github.com/vim/vim/commit/bbea47075cc4e7826e9f8c203e4272ba023ed7b0
Author: Bram Moolenaar <Bram@vim.org>
Date: Tue Jan 1 13:20:31 2019 +0100
patch 8.1.0673: functionality for signs is spread out over several files
Problem: Functionality for signs is spread out over several files.
Solution: Move most of the sign functionality into sign.c. (Yegappan
Lakshmanan, closes #3751)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Tue, 01 Jan 2019 13:30:09 +0100 |
parents | c6c306c5027f |
children | 273649cad196 |
comparison
equal
deleted
inserted
replaced
15329:9a739a3d145e | 15330:a6330a49e036 |
---|---|
7577 do_helptags(dirname, add_help_tags); | 7577 do_helptags(dirname, add_help_tags); |
7578 vim_free(dirname); | 7578 vim_free(dirname); |
7579 } | 7579 } |
7580 } | 7580 } |
7581 | 7581 |
7582 #if defined(FEAT_SIGNS) || defined(PROTO) | |
7583 | |
7584 /* | |
7585 * Struct to hold the sign properties. | |
7586 */ | |
7587 typedef struct sign sign_T; | |
7588 | |
7589 struct sign | |
7590 { | |
7591 sign_T *sn_next; /* next sign in list */ | |
7592 int sn_typenr; /* type number of sign */ | |
7593 char_u *sn_name; /* name of sign */ | |
7594 char_u *sn_icon; /* name of pixmap */ | |
7595 # ifdef FEAT_SIGN_ICONS | |
7596 void *sn_image; /* icon image */ | |
7597 # endif | |
7598 char_u *sn_text; /* text used instead of pixmap */ | |
7599 int sn_line_hl; /* highlight ID for line */ | |
7600 int sn_text_hl; /* highlight ID for text */ | |
7601 }; | |
7602 | |
7603 static sign_T *first_sign = NULL; | |
7604 static int next_sign_typenr = 1; | |
7605 | |
7606 static void sign_list_defined(sign_T *sp); | |
7607 static void sign_undefine(sign_T *sp, sign_T *sp_prev); | |
7608 | |
7609 static char *cmds[] = { | |
7610 "define", | |
7611 # define SIGNCMD_DEFINE 0 | |
7612 "undefine", | |
7613 # define SIGNCMD_UNDEFINE 1 | |
7614 "list", | |
7615 # define SIGNCMD_LIST 2 | |
7616 "place", | |
7617 # define SIGNCMD_PLACE 3 | |
7618 "unplace", | |
7619 # define SIGNCMD_UNPLACE 4 | |
7620 "jump", | |
7621 # define SIGNCMD_JUMP 5 | |
7622 NULL | |
7623 # define SIGNCMD_LAST 6 | |
7624 }; | |
7625 | |
7626 /* | |
7627 * Find index of a ":sign" subcmd from its name. | |
7628 * "*end_cmd" must be writable. | |
7629 */ | |
7630 static int | |
7631 sign_cmd_idx( | |
7632 char_u *begin_cmd, /* begin of sign subcmd */ | |
7633 char_u *end_cmd) /* just after sign subcmd */ | |
7634 { | |
7635 int idx; | |
7636 char save = *end_cmd; | |
7637 | |
7638 *end_cmd = NUL; | |
7639 for (idx = 0; ; ++idx) | |
7640 if (cmds[idx] == NULL || STRCMP(begin_cmd, cmds[idx]) == 0) | |
7641 break; | |
7642 *end_cmd = save; | |
7643 return idx; | |
7644 } | |
7645 | |
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 *sign_id = sign_group_get_next_signid(buf, sign_group); | |
7875 | |
7876 if (lnum > 0) | |
7877 // ":sign place {id} line={lnum} name={name} file={fname}": | |
7878 // place a sign | |
7879 buf_addsign(buf, *sign_id, sign_group, prio, lnum, sp->sn_typenr); | |
7880 else | |
7881 // ":sign place {id} file={fname}": change sign type | |
7882 lnum = buf_change_sign_type(buf, *sign_id, sign_group, sp->sn_typenr); | |
7883 if (lnum > 0) | |
7884 update_debug_sign(buf, lnum); | |
7885 else | |
7886 { | |
7887 EMSG2(_("E885: Not possible to change sign %s"), sign_name); | |
7888 return FAIL; | |
7889 } | |
7890 | |
7891 return OK; | |
7892 } | |
7893 | |
7894 /* | |
7895 * Unplace the specified sign | |
7896 */ | |
7897 int | |
7898 sign_unplace(int sign_id, char_u *sign_group, buf_T *buf, linenr_T atlnum) | |
7899 { | |
7900 if (buf->b_signlist == NULL) // No signs in the buffer | |
7901 return OK; | |
7902 | |
7903 if (sign_id == 0) | |
7904 { | |
7905 // Delete all the signs in the specified buffer | |
7906 redraw_buf_later(buf, NOT_VALID); | |
7907 buf_delete_signs(buf, sign_group); | |
7908 } | |
7909 else | |
7910 { | |
7911 linenr_T lnum; | |
7912 | |
7913 // Delete only the specified signs | |
7914 lnum = buf_delsign(buf, atlnum, sign_id, sign_group); | |
7915 if (lnum == 0) | |
7916 return FAIL; | |
7917 } | |
7918 | |
7919 return OK; | |
7920 } | |
7921 | |
7922 /* | |
7923 * Unplace the sign at the current cursor line. | |
7924 */ | |
7925 static void | |
7926 sign_unplace_at_cursor(char_u *groupname) | |
7927 { | |
7928 int id = -1; | |
7929 | |
7930 id = buf_findsign_id(curwin->w_buffer, curwin->w_cursor.lnum, groupname); | |
7931 if (id > 0) | |
7932 sign_unplace(id, groupname, curwin->w_buffer, curwin->w_cursor.lnum); | |
7933 else | |
7934 EMSG(_("E159: Missing sign number")); | |
7935 } | |
7936 | |
7937 /* | |
7938 * sign define command | |
7939 * ":sign define {name} ..." | |
7940 */ | |
7941 static void | |
7942 sign_define_cmd(char_u *sign_name, char_u *cmdline) | |
7943 { | |
7944 char_u *arg; | |
7945 char_u *p = cmdline; | |
7946 char_u *icon = NULL; | |
7947 char_u *text = NULL; | |
7948 char_u *linehl = NULL; | |
7949 char_u *texthl = NULL; | |
7950 int failed = FALSE; | |
7951 | |
7952 // set values for a defined sign. | |
7953 for (;;) | |
7954 { | |
7955 arg = skipwhite(p); | |
7956 if (*arg == NUL) | |
7957 break; | |
7958 p = skiptowhite_esc(arg); | |
7959 if (STRNCMP(arg, "icon=", 5) == 0) | |
7960 { | |
7961 arg += 5; | |
7962 icon = vim_strnsave(arg, (int)(p - arg)); | |
7963 } | |
7964 else if (STRNCMP(arg, "text=", 5) == 0) | |
7965 { | |
7966 arg += 5; | |
7967 text = vim_strnsave(arg, (int)(p - arg)); | |
7968 } | |
7969 else if (STRNCMP(arg, "linehl=", 7) == 0) | |
7970 { | |
7971 arg += 7; | |
7972 linehl = vim_strnsave(arg, (int)(p - arg)); | |
7973 } | |
7974 else if (STRNCMP(arg, "texthl=", 7) == 0) | |
7975 { | |
7976 arg += 7; | |
7977 texthl = vim_strnsave(arg, (int)(p - arg)); | |
7978 } | |
7979 else | |
7980 { | |
7981 EMSG2(_(e_invarg2), arg); | |
7982 failed = TRUE; | |
7983 break; | |
7984 } | |
7985 } | |
7986 | |
7987 if (!failed) | |
7988 sign_define_by_name(sign_name, icon, linehl, text, texthl); | |
7989 | |
7990 vim_free(icon); | |
7991 vim_free(text); | |
7992 vim_free(linehl); | |
7993 vim_free(texthl); | |
7994 } | |
7995 | |
7996 /* | |
7997 * :sign place command | |
7998 */ | |
7999 static void | |
8000 sign_place_cmd( | |
8001 buf_T *buf, | |
8002 linenr_T lnum, | |
8003 char_u *sign_name, | |
8004 int id, | |
8005 char_u *group, | |
8006 int prio) | |
8007 { | |
8008 if (id <= 0) | |
8009 { | |
8010 // List signs placed in a file/buffer | |
8011 // :sign place file={fname} | |
8012 // :sign place group={group} file={fname} | |
8013 // :sign place group=* file={fname} | |
8014 // :sign place buffer={nr} | |
8015 // :sign place group={group} buffer={nr} | |
8016 // :sign place group=* buffer={nr} | |
8017 // :sign place | |
8018 // :sign place group={group} | |
8019 // :sign place group=* | |
8020 if (lnum >= 0 || sign_name != NULL || | |
8021 (group != NULL && *group == '\0')) | |
8022 EMSG(_(e_invarg)); | |
8023 else | |
8024 sign_list_placed(buf, group); | |
8025 } | |
8026 else | |
8027 { | |
8028 // Place a new sign | |
8029 if (sign_name == NULL || buf == NULL || | |
8030 (group != NULL && *group == '\0')) | |
8031 { | |
8032 EMSG(_(e_invarg)); | |
8033 return; | |
8034 } | |
8035 | |
8036 sign_place(&id, group, sign_name, buf, lnum, prio); | |
8037 } | |
8038 } | |
8039 | |
8040 /* | |
8041 * :sign unplace command | |
8042 */ | |
8043 static void | |
8044 sign_unplace_cmd( | |
8045 buf_T *buf, | |
8046 linenr_T lnum, | |
8047 char_u *sign_name, | |
8048 int id, | |
8049 char_u *group) | |
8050 { | |
8051 if (lnum >= 0 || sign_name != NULL || (group != NULL && *group == '\0')) | |
8052 { | |
8053 EMSG(_(e_invarg)); | |
8054 return; | |
8055 } | |
8056 | |
8057 if (id == -2) | |
8058 { | |
8059 if (buf != NULL) | |
8060 // :sign unplace * file={fname} | |
8061 // :sign unplace * group={group} file={fname} | |
8062 // :sign unplace * group=* file={fname} | |
8063 // :sign unplace * buffer={nr} | |
8064 // :sign unplace * group={group} buffer={nr} | |
8065 // :sign unplace * group=* buffer={nr} | |
8066 sign_unplace(0, group, buf, 0); | |
8067 else | |
8068 // :sign unplace * | |
8069 // :sign unplace * group={group} | |
8070 // :sign unplace * group=* | |
8071 FOR_ALL_BUFFERS(buf) | |
8072 if (buf->b_signlist != NULL) | |
8073 buf_delete_signs(buf, group); | |
8074 } | |
8075 else | |
8076 { | |
8077 if (buf != NULL) | |
8078 // :sign unplace {id} file={fname} | |
8079 // :sign unplace {id} group={group} file={fname} | |
8080 // :sign unplace {id} group=* file={fname} | |
8081 // :sign unplace {id} buffer={nr} | |
8082 // :sign unplace {id} group={group} buffer={nr} | |
8083 // :sign unplace {id} group=* buffer={nr} | |
8084 sign_unplace(id, group, buf, 0); | |
8085 else | |
8086 { | |
8087 if (id == -1) | |
8088 { | |
8089 // :sign unplace group={group} | |
8090 // :sign unplace group=* | |
8091 sign_unplace_at_cursor(group); | |
8092 } | |
8093 else | |
8094 { | |
8095 // :sign unplace {id} | |
8096 // :sign unplace {id} group={group} | |
8097 // :sign unplace {id} group=* | |
8098 FOR_ALL_BUFFERS(buf) | |
8099 sign_unplace(id, group, buf, 0); | |
8100 } | |
8101 } | |
8102 } | |
8103 } | |
8104 | |
8105 /* | |
8106 * Jump to a placed sign | |
8107 * :sign jump {id} file={fname} | |
8108 * :sign jump {id} buffer={nr} | |
8109 * :sign jump {id} group={group} file={fname} | |
8110 * :sign jump {id} group={group} buffer={nr} | |
8111 */ | |
8112 static void | |
8113 sign_jump_cmd( | |
8114 buf_T *buf, | |
8115 linenr_T lnum, | |
8116 char_u *sign_name, | |
8117 int id, | |
8118 char_u *group) | |
8119 { | |
8120 if (buf == NULL && sign_name == NULL && group == NULL && id == -1) | |
8121 { | |
8122 EMSG(_(e_argreq)); | |
8123 return; | |
8124 } | |
8125 | |
8126 if (buf == NULL || (group != NULL && *group == '\0') || | |
8127 lnum >= 0 || sign_name != NULL) | |
8128 { | |
8129 // File or buffer is not specified or an empty group is used | |
8130 // or a line number or a sign name is specified. | |
8131 EMSG(_(e_invarg)); | |
8132 return; | |
8133 } | |
8134 | |
8135 if ((lnum = buf_findsign(buf, id, group)) <= 0) | |
8136 { | |
8137 EMSGN(_("E157: Invalid sign ID: %ld"), id); | |
8138 return; | |
8139 } | |
8140 | |
8141 // goto a sign ... | |
8142 if (buf_jump_open_win(buf) != NULL) | |
8143 { // ... in a current window | |
8144 curwin->w_cursor.lnum = lnum; | |
8145 check_cursor_lnum(); | |
8146 beginline(BL_WHITE); | |
8147 } | |
8148 else | |
8149 { // ... not currently in a window | |
8150 char_u *cmd; | |
8151 | |
8152 if (buf->b_fname == NULL) | |
8153 { | |
8154 EMSG(_("E934: Cannot jump to a buffer that does not have a name")); | |
8155 return; | |
8156 } | |
8157 cmd = alloc((unsigned)STRLEN(buf->b_fname) + 25); | |
8158 if (cmd == NULL) | |
8159 return; | |
8160 sprintf((char *)cmd, "e +%ld %s", (long)lnum, buf->b_fname); | |
8161 do_cmdline_cmd(cmd); | |
8162 vim_free(cmd); | |
8163 } | |
8164 # ifdef FEAT_FOLDING | |
8165 foldOpenCursor(); | |
8166 # endif | |
8167 } | |
8168 | |
8169 /* | |
8170 * Parse the command line arguments for the ":sign place", ":sign unplace" and | |
8171 * ":sign jump" commands. | |
8172 * The supported arguments are: line={lnum} name={name} group={group} | |
8173 * priority={prio} and file={fname} or buffer={nr}. | |
8174 */ | |
8175 static int | |
8176 parse_sign_cmd_args( | |
8177 int cmd, | |
8178 char_u *arg, | |
8179 char_u **sign_name, | |
8180 int *signid, | |
8181 char_u **group, | |
8182 int *prio, | |
8183 buf_T **buf, | |
8184 linenr_T *lnum) | |
8185 { | |
8186 char_u *arg1; | |
8187 char_u *name; | |
8188 char_u *filename = NULL; | |
8189 | |
8190 // first arg could be placed sign id | |
8191 arg1 = arg; | |
8192 if (VIM_ISDIGIT(*arg)) | |
8193 { | |
8194 *signid = getdigits(&arg); | |
8195 if (!VIM_ISWHITE(*arg) && *arg != NUL) | |
8196 { | |
8197 *signid = -1; | |
8198 arg = arg1; | |
8199 } | |
8200 else | |
8201 arg = skipwhite(arg); | |
8202 } | |
8203 | |
8204 while (*arg != NUL) | |
8205 { | |
8206 if (STRNCMP(arg, "line=", 5) == 0) | |
8207 { | |
8208 arg += 5; | |
8209 *lnum = atoi((char *)arg); | |
8210 arg = skiptowhite(arg); | |
8211 } | |
8212 else if (STRNCMP(arg, "*", 1) == 0 && cmd == SIGNCMD_UNPLACE) | |
8213 { | |
8214 if (*signid != -1) | |
8215 { | |
8216 EMSG(_(e_invarg)); | |
8217 return FAIL; | |
8218 } | |
8219 *signid = -2; | |
8220 arg = skiptowhite(arg + 1); | |
8221 } | |
8222 else if (STRNCMP(arg, "name=", 5) == 0) | |
8223 { | |
8224 arg += 5; | |
8225 name = arg; | |
8226 arg = skiptowhite(arg); | |
8227 if (*arg != NUL) | |
8228 *arg++ = NUL; | |
8229 while (name[0] == '0' && name[1] != NUL) | |
8230 ++name; | |
8231 *sign_name = name; | |
8232 } | |
8233 else if (STRNCMP(arg, "group=", 6) == 0) | |
8234 { | |
8235 arg += 6; | |
8236 *group = arg; | |
8237 arg = skiptowhite(arg); | |
8238 if (*arg != NUL) | |
8239 *arg++ = NUL; | |
8240 } | |
8241 else if (STRNCMP(arg, "priority=", 9) == 0) | |
8242 { | |
8243 arg += 9; | |
8244 *prio = atoi((char *)arg); | |
8245 arg = skiptowhite(arg); | |
8246 } | |
8247 else if (STRNCMP(arg, "file=", 5) == 0) | |
8248 { | |
8249 arg += 5; | |
8250 filename = arg; | |
8251 *buf = buflist_findname_exp(arg); | |
8252 break; | |
8253 } | |
8254 else if (STRNCMP(arg, "buffer=", 7) == 0) | |
8255 { | |
8256 arg += 7; | |
8257 filename = arg; | |
8258 *buf = buflist_findnr((int)getdigits(&arg)); | |
8259 if (*skipwhite(arg) != NUL) | |
8260 EMSG(_(e_trailing)); | |
8261 break; | |
8262 } | |
8263 else | |
8264 { | |
8265 EMSG(_(e_invarg)); | |
8266 return FAIL; | |
8267 } | |
8268 arg = skipwhite(arg); | |
8269 } | |
8270 | |
8271 if (filename != NULL && *buf == NULL) | |
8272 { | |
8273 EMSG2(_("E158: Invalid buffer name: %s"), filename); | |
8274 return FAIL; | |
8275 } | |
8276 | |
8277 return OK; | |
8278 } | |
8279 | |
8280 /* | |
8281 * ":sign" command | |
8282 */ | |
8283 void | |
8284 ex_sign(exarg_T *eap) | |
8285 { | |
8286 char_u *arg = eap->arg; | |
8287 char_u *p; | |
8288 int idx; | |
8289 sign_T *sp; | |
8290 buf_T *buf = NULL; | |
8291 | |
8292 // Parse the subcommand. | |
8293 p = skiptowhite(arg); | |
8294 idx = sign_cmd_idx(arg, p); | |
8295 if (idx == SIGNCMD_LAST) | |
8296 { | |
8297 EMSG2(_("E160: Unknown sign command: %s"), arg); | |
8298 return; | |
8299 } | |
8300 arg = skipwhite(p); | |
8301 | |
8302 if (idx <= SIGNCMD_LIST) | |
8303 { | |
8304 // Define, undefine or list signs. | |
8305 if (idx == SIGNCMD_LIST && *arg == NUL) | |
8306 { | |
8307 // ":sign list": list all defined signs | |
8308 for (sp = first_sign; sp != NULL && !got_int; sp = sp->sn_next) | |
8309 sign_list_defined(sp); | |
8310 } | |
8311 else if (*arg == NUL) | |
8312 EMSG(_("E156: Missing sign name")); | |
8313 else | |
8314 { | |
8315 char_u *name; | |
8316 | |
8317 // Isolate the sign name. If it's a number skip leading zeroes, | |
8318 // so that "099" and "99" are the same sign. But keep "0". | |
8319 p = skiptowhite(arg); | |
8320 if (*p != NUL) | |
8321 *p++ = NUL; | |
8322 while (arg[0] == '0' && arg[1] != NUL) | |
8323 ++arg; | |
8324 name = vim_strsave(arg); | |
8325 | |
8326 if (idx == SIGNCMD_DEFINE) | |
8327 sign_define_cmd(name, p); | |
8328 else if (idx == SIGNCMD_LIST) | |
8329 // ":sign list {name}" | |
8330 sign_list_by_name(name); | |
8331 else | |
8332 // ":sign undefine {name}" | |
8333 sign_undefine_by_name(name); | |
8334 | |
8335 vim_free(name); | |
8336 return; | |
8337 } | |
8338 } | |
8339 else | |
8340 { | |
8341 int id = -1; | |
8342 linenr_T lnum = -1; | |
8343 char_u *sign_name = NULL; | |
8344 char_u *group = NULL; | |
8345 int prio = SIGN_DEF_PRIO; | |
8346 | |
8347 // Parse command line arguments | |
8348 if (parse_sign_cmd_args(idx, arg, &sign_name, &id, &group, &prio, | |
8349 &buf, &lnum) == FAIL) | |
8350 return; | |
8351 | |
8352 if (idx == SIGNCMD_PLACE) | |
8353 sign_place_cmd(buf, lnum, sign_name, id, group, prio); | |
8354 else if (idx == SIGNCMD_UNPLACE) | |
8355 sign_unplace_cmd(buf, lnum, sign_name, id, group); | |
8356 else if (idx == SIGNCMD_JUMP) | |
8357 sign_jump_cmd(buf, lnum, sign_name, id, group); | |
8358 } | |
8359 } | |
8360 | |
8361 /* | |
8362 * Return information about a specified sign | |
8363 */ | |
8364 static void | |
8365 sign_getinfo(sign_T *sp, dict_T *retdict) | |
8366 { | |
8367 char_u *p; | |
8368 | |
8369 dict_add_string(retdict, "name", (char_u *)sp->sn_name); | |
8370 if (sp->sn_icon != NULL) | |
8371 dict_add_string(retdict, "icon", (char_u *)sp->sn_icon); | |
8372 if (sp->sn_text != NULL) | |
8373 dict_add_string(retdict, "text", (char_u *)sp->sn_text); | |
8374 if (sp->sn_line_hl > 0) | |
8375 { | |
8376 p = get_highlight_name_ext(NULL, sp->sn_line_hl - 1, FALSE); | |
8377 if (p == NULL) | |
8378 p = (char_u *)"NONE"; | |
8379 dict_add_string(retdict, "linehl", (char_u *)p); | |
8380 } | |
8381 if (sp->sn_text_hl > 0) | |
8382 { | |
8383 p = get_highlight_name_ext(NULL, sp->sn_text_hl - 1, FALSE); | |
8384 if (p == NULL) | |
8385 p = (char_u *)"NONE"; | |
8386 dict_add_string(retdict, "texthl", (char_u *)p); | |
8387 } | |
8388 } | |
8389 | |
8390 /* | |
8391 * If 'name' is NULL, return a list of all the defined signs. | |
8392 * Otherwise, return information about the specified sign. | |
8393 */ | |
8394 void | |
8395 sign_getlist(char_u *name, list_T *retlist) | |
8396 { | |
8397 sign_T *sp = first_sign; | |
8398 dict_T *dict; | |
8399 | |
8400 if (name != NULL) | |
8401 { | |
8402 sp = sign_find(name, NULL); | |
8403 if (sp == NULL) | |
8404 return; | |
8405 } | |
8406 | |
8407 for (; sp != NULL && !got_int; sp = sp->sn_next) | |
8408 { | |
8409 if ((dict = dict_alloc_id(aid_sign_getlist)) == NULL) | |
8410 return; | |
8411 if (list_append_dict(retlist, dict) == FAIL) | |
8412 return; | |
8413 sign_getinfo(sp, dict); | |
8414 | |
8415 if (name != NULL) // handle only the specified sign | |
8416 break; | |
8417 } | |
8418 } | |
8419 | |
8420 /* | |
8421 * Return information about all the signs placed in a buffer | |
8422 */ | |
8423 static void | |
8424 sign_get_placed_in_buf( | |
8425 buf_T *buf, | |
8426 linenr_T lnum, | |
8427 int sign_id, | |
8428 char_u *sign_group, | |
8429 list_T *retlist) | |
8430 { | |
8431 dict_T *d; | |
8432 list_T *l; | |
8433 signlist_T *sign; | |
8434 dict_T *sdict; | |
8435 | |
8436 if ((d = dict_alloc_id(aid_sign_getplaced_dict)) == NULL) | |
8437 return; | |
8438 list_append_dict(retlist, d); | |
8439 | |
8440 dict_add_number(d, "bufnr", (long)buf->b_fnum); | |
8441 | |
8442 if ((l = list_alloc_id(aid_sign_getplaced_list)) == NULL) | |
8443 return; | |
8444 dict_add_list(d, "signs", l); | |
8445 | |
8446 FOR_ALL_SIGNS_IN_BUF(buf, sign) | |
8447 { | |
8448 if (!sign_in_group(sign, sign_group)) | |
8449 continue; | |
8450 if ((lnum == 0 && sign_id == 0) || | |
8451 (sign_id == 0 && lnum == sign->lnum) || | |
8452 (lnum == 0 && sign_id == sign->id) || | |
8453 (lnum == sign->lnum && sign_id == sign->id)) | |
8454 { | |
8455 if ((sdict = sign_get_info(sign)) != NULL) | |
8456 list_append_dict(l, sdict); | |
8457 } | |
8458 } | |
8459 } | |
8460 | |
8461 /* | |
8462 * Get a list of signs placed in buffer 'buf'. If 'num' is non-zero, return the | |
8463 * sign placed at the line number. If 'lnum' is zero, return all the signs | |
8464 * placed in 'buf'. If 'buf' is NULL, return signs placed in all the buffers. | |
8465 */ | |
8466 void | |
8467 sign_get_placed( | |
8468 buf_T *buf, | |
8469 linenr_T lnum, | |
8470 int sign_id, | |
8471 char_u *sign_group, | |
8472 list_T *retlist) | |
8473 { | |
8474 if (buf != NULL) | |
8475 sign_get_placed_in_buf(buf, lnum, sign_id, sign_group, retlist); | |
8476 else | |
8477 { | |
8478 FOR_ALL_BUFFERS(buf) | |
8479 { | |
8480 if (buf->b_signlist != NULL) | |
8481 sign_get_placed_in_buf(buf, 0, sign_id, sign_group, retlist); | |
8482 } | |
8483 } | |
8484 } | |
8485 | |
8486 # if defined(FEAT_SIGN_ICONS) || defined(PROTO) | |
8487 /* | |
8488 * Allocate the icons. Called when the GUI has started. Allows defining | |
8489 * signs before it starts. | |
8490 */ | |
8491 void | |
8492 sign_gui_started(void) | |
8493 { | |
8494 sign_T *sp; | |
8495 | |
8496 for (sp = first_sign; sp != NULL; sp = sp->sn_next) | |
8497 if (sp->sn_icon != NULL) | |
8498 sp->sn_image = gui_mch_register_sign(sp->sn_icon); | |
8499 } | |
8500 # endif | |
8501 | |
8502 /* | |
8503 * List one sign. | |
8504 */ | |
8505 static void | |
8506 sign_list_defined(sign_T *sp) | |
8507 { | |
8508 char_u *p; | |
8509 | |
8510 smsg((char_u *)"sign %s", sp->sn_name); | |
8511 if (sp->sn_icon != NULL) | |
8512 { | |
8513 MSG_PUTS(" icon="); | |
8514 msg_outtrans(sp->sn_icon); | |
8515 # ifdef FEAT_SIGN_ICONS | |
8516 if (sp->sn_image == NULL) | |
8517 MSG_PUTS(_(" (NOT FOUND)")); | |
8518 # else | |
8519 MSG_PUTS(_(" (not supported)")); | |
8520 # endif | |
8521 } | |
8522 if (sp->sn_text != NULL) | |
8523 { | |
8524 MSG_PUTS(" text="); | |
8525 msg_outtrans(sp->sn_text); | |
8526 } | |
8527 if (sp->sn_line_hl > 0) | |
8528 { | |
8529 MSG_PUTS(" linehl="); | |
8530 p = get_highlight_name_ext(NULL, sp->sn_line_hl - 1, FALSE); | |
8531 if (p == NULL) | |
8532 MSG_PUTS("NONE"); | |
8533 else | |
8534 msg_puts(p); | |
8535 } | |
8536 if (sp->sn_text_hl > 0) | |
8537 { | |
8538 MSG_PUTS(" texthl="); | |
8539 p = get_highlight_name_ext(NULL, sp->sn_text_hl - 1, FALSE); | |
8540 if (p == NULL) | |
8541 MSG_PUTS("NONE"); | |
8542 else | |
8543 msg_puts(p); | |
8544 } | |
8545 } | |
8546 | |
8547 /* | |
8548 * Undefine a sign and free its memory. | |
8549 */ | |
8550 static void | |
8551 sign_undefine(sign_T *sp, sign_T *sp_prev) | |
8552 { | |
8553 vim_free(sp->sn_name); | |
8554 vim_free(sp->sn_icon); | |
8555 # ifdef FEAT_SIGN_ICONS | |
8556 if (sp->sn_image != NULL) | |
8557 { | |
8558 out_flush(); | |
8559 gui_mch_destroy_sign(sp->sn_image); | |
8560 } | |
8561 # endif | |
8562 vim_free(sp->sn_text); | |
8563 if (sp_prev == NULL) | |
8564 first_sign = sp->sn_next; | |
8565 else | |
8566 sp_prev->sn_next = sp->sn_next; | |
8567 vim_free(sp); | |
8568 } | |
8569 | |
8570 /* | |
8571 * Get highlighting attribute for sign "typenr". | |
8572 * If "line" is TRUE: line highl, if FALSE: text highl. | |
8573 */ | |
8574 int | |
8575 sign_get_attr(int typenr, int line) | |
8576 { | |
8577 sign_T *sp; | |
8578 | |
8579 for (sp = first_sign; sp != NULL; sp = sp->sn_next) | |
8580 if (sp->sn_typenr == typenr) | |
8581 { | |
8582 if (line) | |
8583 { | |
8584 if (sp->sn_line_hl > 0) | |
8585 return syn_id2attr(sp->sn_line_hl); | |
8586 } | |
8587 else | |
8588 { | |
8589 if (sp->sn_text_hl > 0) | |
8590 return syn_id2attr(sp->sn_text_hl); | |
8591 } | |
8592 break; | |
8593 } | |
8594 return 0; | |
8595 } | |
8596 | |
8597 /* | |
8598 * Get text mark for sign "typenr". | |
8599 * Returns NULL if there isn't one. | |
8600 */ | |
8601 char_u * | |
8602 sign_get_text(int typenr) | |
8603 { | |
8604 sign_T *sp; | |
8605 | |
8606 for (sp = first_sign; sp != NULL; sp = sp->sn_next) | |
8607 if (sp->sn_typenr == typenr) | |
8608 return sp->sn_text; | |
8609 return NULL; | |
8610 } | |
8611 | |
8612 # if defined(FEAT_SIGN_ICONS) || defined(PROTO) | |
8613 void * | |
8614 sign_get_image( | |
8615 int typenr) /* the attribute which may have a sign */ | |
8616 { | |
8617 sign_T *sp; | |
8618 | |
8619 for (sp = first_sign; sp != NULL; sp = sp->sn_next) | |
8620 if (sp->sn_typenr == typenr) | |
8621 return sp->sn_image; | |
8622 return NULL; | |
8623 } | |
8624 # endif | |
8625 | |
8626 /* | |
8627 * Get the name of a sign by its typenr. | |
8628 */ | |
8629 char_u * | |
8630 sign_typenr2name(int typenr) | |
8631 { | |
8632 sign_T *sp; | |
8633 | |
8634 for (sp = first_sign; sp != NULL; sp = sp->sn_next) | |
8635 if (sp->sn_typenr == typenr) | |
8636 return sp->sn_name; | |
8637 return (char_u *)_("[Deleted]"); | |
8638 } | |
8639 | |
8640 /* | |
8641 * Undefine/free all signs. | |
8642 */ | |
8643 void | |
8644 free_signs(void) | |
8645 { | |
8646 while (first_sign != NULL) | |
8647 sign_undefine(first_sign, NULL); | |
8648 } | |
8649 | |
8650 # if defined(FEAT_CMDL_COMPL) || defined(PROTO) | |
8651 static enum | |
8652 { | |
8653 EXP_SUBCMD, /* expand :sign sub-commands */ | |
8654 EXP_DEFINE, /* expand :sign define {name} args */ | |
8655 EXP_PLACE, /* expand :sign place {id} args */ | |
8656 EXP_UNPLACE, /* expand :sign unplace" */ | |
8657 EXP_SIGN_NAMES /* expand with name of placed signs */ | |
8658 } expand_what; | |
8659 | |
8660 /* | |
8661 * Function given to ExpandGeneric() to obtain the sign command | |
8662 * expansion. | |
8663 */ | |
8664 char_u * | |
8665 get_sign_name(expand_T *xp UNUSED, int idx) | |
8666 { | |
8667 sign_T *sp; | |
8668 int current_idx; | |
8669 | |
8670 switch (expand_what) | |
8671 { | |
8672 case EXP_SUBCMD: | |
8673 return (char_u *)cmds[idx]; | |
8674 case EXP_DEFINE: | |
8675 { | |
8676 char *define_arg[] = | |
8677 { | |
8678 "icon=", "linehl=", "text=", "texthl=", NULL | |
8679 }; | |
8680 return (char_u *)define_arg[idx]; | |
8681 } | |
8682 case EXP_PLACE: | |
8683 { | |
8684 char *place_arg[] = | |
8685 { | |
8686 "line=", "name=", "group=", "priority=", "file=", | |
8687 "buffer=", NULL | |
8688 }; | |
8689 return (char_u *)place_arg[idx]; | |
8690 } | |
8691 case EXP_UNPLACE: | |
8692 { | |
8693 char *unplace_arg[] = { "group=", "file=", "buffer=", NULL }; | |
8694 return (char_u *)unplace_arg[idx]; | |
8695 } | |
8696 case EXP_SIGN_NAMES: | |
8697 /* Complete with name of signs already defined */ | |
8698 current_idx = 0; | |
8699 for (sp = first_sign; sp != NULL; sp = sp->sn_next) | |
8700 if (current_idx++ == idx) | |
8701 return sp->sn_name; | |
8702 return NULL; | |
8703 default: | |
8704 return NULL; | |
8705 } | |
8706 } | |
8707 | |
8708 /* | |
8709 * Handle command line completion for :sign command. | |
8710 */ | |
8711 void | |
8712 set_context_in_sign_cmd(expand_T *xp, char_u *arg) | |
8713 { | |
8714 char_u *p; | |
8715 char_u *end_subcmd; | |
8716 char_u *last; | |
8717 int cmd_idx; | |
8718 char_u *begin_subcmd_args; | |
8719 | |
8720 /* Default: expand subcommands. */ | |
8721 xp->xp_context = EXPAND_SIGN; | |
8722 expand_what = EXP_SUBCMD; | |
8723 xp->xp_pattern = arg; | |
8724 | |
8725 end_subcmd = skiptowhite(arg); | |
8726 if (*end_subcmd == NUL) | |
8727 /* expand subcmd name | |
8728 * :sign {subcmd}<CTRL-D>*/ | |
8729 return; | |
8730 | |
8731 cmd_idx = sign_cmd_idx(arg, end_subcmd); | |
8732 | |
8733 /* :sign {subcmd} {subcmd_args} | |
8734 * | | |
8735 * begin_subcmd_args */ | |
8736 begin_subcmd_args = skipwhite(end_subcmd); | |
8737 p = skiptowhite(begin_subcmd_args); | |
8738 if (*p == NUL) | |
8739 { | |
8740 /* | |
8741 * Expand first argument of subcmd when possible. | |
8742 * For ":jump {id}" and ":unplace {id}", we could | |
8743 * possibly expand the ids of all signs already placed. | |
8744 */ | |
8745 xp->xp_pattern = begin_subcmd_args; | |
8746 switch (cmd_idx) | |
8747 { | |
8748 case SIGNCMD_LIST: | |
8749 case SIGNCMD_UNDEFINE: | |
8750 /* :sign list <CTRL-D> | |
8751 * :sign undefine <CTRL-D> */ | |
8752 expand_what = EXP_SIGN_NAMES; | |
8753 break; | |
8754 default: | |
8755 xp->xp_context = EXPAND_NOTHING; | |
8756 } | |
8757 return; | |
8758 } | |
8759 | |
8760 /* expand last argument of subcmd */ | |
8761 | |
8762 /* :sign define {name} {args}... | |
8763 * | | |
8764 * p */ | |
8765 | |
8766 /* Loop until reaching last argument. */ | |
8767 do | |
8768 { | |
8769 p = skipwhite(p); | |
8770 last = p; | |
8771 p = skiptowhite(p); | |
8772 } while (*p != NUL); | |
8773 | |
8774 p = vim_strchr(last, '='); | |
8775 | |
8776 /* :sign define {name} {args}... {last}= | |
8777 * | | | |
8778 * last p */ | |
8779 if (p == NULL) | |
8780 { | |
8781 /* Expand last argument name (before equal sign). */ | |
8782 xp->xp_pattern = last; | |
8783 switch (cmd_idx) | |
8784 { | |
8785 case SIGNCMD_DEFINE: | |
8786 expand_what = EXP_DEFINE; | |
8787 break; | |
8788 case SIGNCMD_PLACE: | |
8789 expand_what = EXP_PLACE; | |
8790 break; | |
8791 case SIGNCMD_JUMP: | |
8792 case SIGNCMD_UNPLACE: | |
8793 expand_what = EXP_UNPLACE; | |
8794 break; | |
8795 default: | |
8796 xp->xp_context = EXPAND_NOTHING; | |
8797 } | |
8798 } | |
8799 else | |
8800 { | |
8801 /* Expand last argument value (after equal sign). */ | |
8802 xp->xp_pattern = p + 1; | |
8803 switch (cmd_idx) | |
8804 { | |
8805 case SIGNCMD_DEFINE: | |
8806 if (STRNCMP(last, "texthl", p - last) == 0 || | |
8807 STRNCMP(last, "linehl", p - last) == 0) | |
8808 xp->xp_context = EXPAND_HIGHLIGHT; | |
8809 else if (STRNCMP(last, "icon", p - last) == 0) | |
8810 xp->xp_context = EXPAND_FILES; | |
8811 else | |
8812 xp->xp_context = EXPAND_NOTHING; | |
8813 break; | |
8814 case SIGNCMD_PLACE: | |
8815 if (STRNCMP(last, "name", p - last) == 0) | |
8816 expand_what = EXP_SIGN_NAMES; | |
8817 else | |
8818 xp->xp_context = EXPAND_NOTHING; | |
8819 break; | |
8820 default: | |
8821 xp->xp_context = EXPAND_NOTHING; | |
8822 } | |
8823 } | |
8824 } | |
8825 # endif | |
8826 #endif | |
8827 | |
8828 /* | 7582 /* |
8829 * Make the user happy. | 7583 * Make the user happy. |
8830 */ | 7584 */ |
8831 void | 7585 void |
8832 ex_smile(exarg_T *eap UNUSED) | 7586 ex_smile(exarg_T *eap UNUSED) |