comparison src/buffer.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 890203d87ee5
children 55ccc2d353bd
comparison
equal deleted inserted replaced
15329:9a739a3d145e 15330:a6330a49e036
5862 win_found: 5862 win_found:
5863 return OK; 5863 return OK;
5864 } 5864 }
5865 #endif 5865 #endif
5866 5866
5867 #if defined(FEAT_SIGNS) || defined(PROTO)
5868 static hashtab_T sg_table; // sign group (signgroup_T) hashtable
5869 static int next_sign_id = 1; // next sign id in the global group
5870
5871 /*
5872 * Initialize data needed for managing signs
5873 */
5874 void
5875 init_signs(void)
5876 {
5877 hash_init(&sg_table); // sign group hash table
5878 }
5879
5880 /*
5881 * A new sign in group 'groupname' is added. If the group is not present,
5882 * create it. Otherwise reference the group.
5883 */
5884 static signgroup_T *
5885 sign_group_ref(char_u *groupname)
5886 {
5887 hash_T hash;
5888 hashitem_T *hi;
5889 signgroup_T *group;
5890
5891 hash = hash_hash(groupname);
5892 hi = hash_lookup(&sg_table, groupname, hash);
5893 if (HASHITEM_EMPTY(hi))
5894 {
5895 // new group
5896 group = (signgroup_T *)alloc(
5897 (unsigned)(sizeof(signgroup_T) + STRLEN(groupname)));
5898 if (group == NULL)
5899 return NULL;
5900 STRCPY(group->sg_name, groupname);
5901 group->refcount = 1;
5902 group->next_sign_id = 1;
5903 hash_add_item(&sg_table, hi, group->sg_name, hash);
5904 }
5905 else
5906 {
5907 // existing group
5908 group = HI2SG(hi);
5909 group->refcount++;
5910 }
5911
5912 return group;
5913 }
5914
5915 /*
5916 * A sign in group 'groupname' is removed. If all the signs in this group are
5917 * removed, then remove the group.
5918 */
5919 static void
5920 sign_group_unref(char_u *groupname)
5921 {
5922 hashitem_T *hi;
5923 signgroup_T *group;
5924
5925 hi = hash_find(&sg_table, groupname);
5926 if (!HASHITEM_EMPTY(hi))
5927 {
5928 group = HI2SG(hi);
5929 group->refcount--;
5930 if (group->refcount == 0)
5931 {
5932 // All the signs in this group are removed
5933 hash_remove(&sg_table, hi);
5934 vim_free(group);
5935 }
5936 }
5937 }
5938
5939 /*
5940 * Get the next free sign identifier in the specified group
5941 */
5942 int
5943 sign_group_get_next_signid(buf_T *buf, char_u *groupname)
5944 {
5945 int id = 1;
5946 signgroup_T *group = NULL;
5947 signlist_T *sign;
5948 hashitem_T *hi;
5949 int found = FALSE;
5950
5951 if (groupname != NULL)
5952 {
5953 hi = hash_find(&sg_table, groupname);
5954 if (HASHITEM_EMPTY(hi))
5955 return id;
5956 group = HI2SG(hi);
5957 }
5958
5959 // Search for the next usuable sign identifier
5960 while (!found)
5961 {
5962 if (group == NULL)
5963 id = next_sign_id++; // global group
5964 else
5965 id = group->next_sign_id++;
5966
5967 // Check whether this sign is already placed in the buffer
5968 found = TRUE;
5969 FOR_ALL_SIGNS_IN_BUF(buf, sign)
5970 {
5971 if (id == sign->id && sign_in_group(sign, groupname))
5972 {
5973 found = FALSE; // sign identifier is in use
5974 break;
5975 }
5976 }
5977 }
5978
5979 return id;
5980 }
5981
5982 /*
5983 * Insert a new sign into the signlist for buffer 'buf' between the 'prev' and
5984 * 'next' signs.
5985 */
5986 static void
5987 insert_sign(
5988 buf_T *buf, // buffer to store sign in
5989 signlist_T *prev, // previous sign entry
5990 signlist_T *next, // next sign entry
5991 int id, // sign ID
5992 char_u *group, // sign group; NULL for global group
5993 int prio, // sign priority
5994 linenr_T lnum, // line number which gets the mark
5995 int typenr) // typenr of sign we are adding
5996 {
5997 signlist_T *newsign;
5998
5999 newsign = (signlist_T *)lalloc_id((long_u)sizeof(signlist_T), FALSE,
6000 aid_insert_sign);
6001 if (newsign != NULL)
6002 {
6003 newsign->id = id;
6004 newsign->lnum = lnum;
6005 newsign->typenr = typenr;
6006 if (group != NULL)
6007 {
6008 newsign->group = sign_group_ref(group);
6009 if (newsign->group == NULL)
6010 {
6011 vim_free(newsign);
6012 return;
6013 }
6014 }
6015 else
6016 newsign->group = NULL;
6017 newsign->priority = prio;
6018 newsign->next = next;
6019 newsign->prev = prev;
6020 if (next != NULL)
6021 next->prev = newsign;
6022
6023 if (prev == NULL)
6024 {
6025 // When adding first sign need to redraw the windows to create the
6026 // column for signs.
6027 if (buf->b_signlist == NULL)
6028 {
6029 redraw_buf_later(buf, NOT_VALID);
6030 changed_cline_bef_curs();
6031 }
6032
6033 // first sign in signlist
6034 buf->b_signlist = newsign;
6035 #ifdef FEAT_NETBEANS_INTG
6036 if (netbeans_active())
6037 buf->b_has_sign_column = TRUE;
6038 #endif
6039 }
6040 else
6041 prev->next = newsign;
6042 }
6043 }
6044
6045 /*
6046 * Insert a new sign sorted by line number and sign priority.
6047 */
6048 static void
6049 insert_sign_by_lnum_prio(
6050 buf_T *buf, // buffer to store sign in
6051 signlist_T *prev, // previous sign entry
6052 int id, // sign ID
6053 char_u *group, // sign group; NULL for global group
6054 int prio, // sign priority
6055 linenr_T lnum, // line number which gets the mark
6056 int typenr) // typenr of sign we are adding
6057 {
6058 signlist_T *sign;
6059
6060 // keep signs sorted by lnum and by priority: insert new sign at
6061 // the proper position in the list for this lnum.
6062 while (prev != NULL && prev->lnum == lnum && prev->priority <= prio)
6063 prev = prev->prev;
6064 if (prev == NULL)
6065 sign = buf->b_signlist;
6066 else
6067 sign = prev->next;
6068
6069 insert_sign(buf, prev, sign, id, group, prio, lnum, typenr);
6070 }
6071
6072 /*
6073 * Returns TRUE if 'sign' is in 'group'.
6074 * A sign can either be in the global group (sign->group == NULL)
6075 * or in a named group. If 'group' is '*', then the sign is part of the group.
6076 */
6077 int
6078 sign_in_group(signlist_T *sign, char_u *group)
6079 {
6080 return ((group != NULL && STRCMP(group, "*") == 0)
6081 || (group == NULL && sign->group == NULL)
6082 || (group != NULL && sign->group != NULL
6083 && STRCMP(group, sign->group->sg_name) == 0));
6084 }
6085
6086 /*
6087 * Return information about a sign in a Dict
6088 */
6089 dict_T *
6090 sign_get_info(signlist_T *sign)
6091 {
6092 dict_T *d;
6093
6094 if ((d = dict_alloc_id(aid_sign_getinfo)) == NULL)
6095 return NULL;
6096 dict_add_number(d, "id", sign->id);
6097 dict_add_string(d, "group", (sign->group == NULL) ?
6098 (char_u *)"" : sign->group->sg_name);
6099 dict_add_number(d, "lnum", sign->lnum);
6100 dict_add_string(d, "name", sign_typenr2name(sign->typenr));
6101 dict_add_number(d, "priority", sign->priority);
6102
6103 return d;
6104 }
6105
6106 /*
6107 * Add the sign into the signlist. Find the right spot to do it though.
6108 */
6109 void
6110 buf_addsign(
6111 buf_T *buf, // buffer to store sign in
6112 int id, // sign ID
6113 char_u *groupname, // sign group
6114 int prio, // sign priority
6115 linenr_T lnum, // line number which gets the mark
6116 int typenr) // typenr of sign we are adding
6117 {
6118 signlist_T *sign; // a sign in the signlist
6119 signlist_T *prev; // the previous sign
6120
6121 prev = NULL;
6122 FOR_ALL_SIGNS_IN_BUF(buf, sign)
6123 {
6124 if (lnum == sign->lnum && id == sign->id &&
6125 sign_in_group(sign, groupname))
6126 {
6127 // Update an existing sign
6128 sign->typenr = typenr;
6129 return;
6130 }
6131 else if (lnum < sign->lnum)
6132 {
6133 insert_sign_by_lnum_prio(buf, prev, id, groupname, prio,
6134 lnum, typenr);
6135 return;
6136 }
6137 prev = sign;
6138 }
6139
6140 insert_sign_by_lnum_prio(buf, prev, id, groupname, prio, lnum, typenr);
6141 return;
6142 }
6143
6144 /*
6145 * For an existing, placed sign "markId" change the type to "typenr".
6146 * Returns the line number of the sign, or zero if the sign is not found.
6147 */
6148 linenr_T
6149 buf_change_sign_type(
6150 buf_T *buf, // buffer to store sign in
6151 int markId, // sign ID
6152 char_u *group, // sign group
6153 int typenr) // typenr of sign we are adding
6154 {
6155 signlist_T *sign; // a sign in the signlist
6156
6157 FOR_ALL_SIGNS_IN_BUF(buf, sign)
6158 {
6159 if (sign->id == markId && sign_in_group(sign, group))
6160 {
6161 sign->typenr = typenr;
6162 return sign->lnum;
6163 }
6164 }
6165
6166 return (linenr_T)0;
6167 }
6168
6169 /*
6170 * Return the type number of the sign at line number 'lnum' in buffer 'buf'
6171 * which has the attribute specifed by 'type'. Returns 0 if a sign is not found
6172 * at the line number or it doesn't have the specified attribute.
6173 */
6174 int
6175 buf_getsigntype(
6176 buf_T *buf,
6177 linenr_T lnum,
6178 int type) /* SIGN_ICON, SIGN_TEXT, SIGN_ANY, SIGN_LINEHL */
6179 {
6180 signlist_T *sign; /* a sign in a b_signlist */
6181
6182 FOR_ALL_SIGNS_IN_BUF(buf, sign)
6183 if (sign->lnum == lnum
6184 && (type == SIGN_ANY
6185 # ifdef FEAT_SIGN_ICONS
6186 || (type == SIGN_ICON
6187 && sign_get_image(sign->typenr) != NULL)
6188 # endif
6189 || (type == SIGN_TEXT
6190 && sign_get_text(sign->typenr) != NULL)
6191 || (type == SIGN_LINEHL
6192 && sign_get_attr(sign->typenr, TRUE) != 0)))
6193 return sign->typenr;
6194 return 0;
6195 }
6196
6197 /*
6198 * Delete sign 'id' in group 'group' from buffer 'buf'.
6199 * If 'id' is zero, then delete all the signs in group 'group'. Otherwise
6200 * delete only the specified sign.
6201 * If 'group' is '*', then delete the sign in all the groups. If 'group' is
6202 * NULL, then delete the sign in the global group. Otherwise delete the sign in
6203 * the specified group.
6204 * Returns the line number of the deleted sign. If multiple signs are deleted,
6205 * then returns the line number of the last sign deleted.
6206 */
6207 linenr_T
6208 buf_delsign(
6209 buf_T *buf, // buffer sign is stored in
6210 linenr_T atlnum, // sign at this line, 0 - at any line
6211 int id, // sign id
6212 char_u *group) // sign group
6213 {
6214 signlist_T **lastp; // pointer to pointer to current sign
6215 signlist_T *sign; // a sign in a b_signlist
6216 signlist_T *next; // the next sign in a b_signlist
6217 linenr_T lnum; // line number whose sign was deleted
6218
6219 lastp = &buf->b_signlist;
6220 lnum = 0;
6221 for (sign = buf->b_signlist; sign != NULL; sign = next)
6222 {
6223 next = sign->next;
6224 if ((id == 0 || sign->id == id) &&
6225 (atlnum == 0 || sign->lnum == atlnum) &&
6226 sign_in_group(sign, group))
6227
6228 {
6229 *lastp = next;
6230 if (next != NULL)
6231 next->prev = sign->prev;
6232 lnum = sign->lnum;
6233 if (sign->group != NULL)
6234 sign_group_unref(sign->group->sg_name);
6235 vim_free(sign);
6236 update_debug_sign(buf, lnum);
6237 // Check whether only one sign needs to be deleted
6238 // If deleting a sign with a specific identifer in a particular
6239 // group or deleting any sign at a particular line number, delete
6240 // only one sign.
6241 if (group == NULL
6242 || (*group != '*' && id != 0)
6243 || (*group == '*' && atlnum != 0))
6244 break;
6245 }
6246 else
6247 lastp = &sign->next;
6248 }
6249
6250 // When deleted the last sign need to redraw the windows to remove the
6251 // sign column.
6252 if (buf->b_signlist == NULL)
6253 {
6254 redraw_buf_later(buf, NOT_VALID);
6255 changed_cline_bef_curs();
6256 }
6257
6258 return lnum;
6259 }
6260
6261
6262 /*
6263 * Find the line number of the sign with the requested id in group 'group'. If
6264 * the sign does not exist, return 0 as the line number. This will still let
6265 * the correct file get loaded.
6266 */
6267 int
6268 buf_findsign(
6269 buf_T *buf, // buffer to store sign in
6270 int id, // sign ID
6271 char_u *group) // sign group
6272 {
6273 signlist_T *sign; // a sign in the signlist
6274
6275 FOR_ALL_SIGNS_IN_BUF(buf, sign)
6276 if (sign->id == id && sign_in_group(sign, group))
6277 return sign->lnum;
6278
6279 return 0;
6280 }
6281
6282 /*
6283 * Return the sign at line 'lnum' in buffer 'buf'. Returns NULL if a sign is
6284 * not found at the line. If 'groupname' is NULL, searches in the global group.
6285 */
6286 static signlist_T *
6287 buf_getsign_at_line(
6288 buf_T *buf, // buffer whose sign we are searching for
6289 linenr_T lnum, // line number of sign
6290 char_u *groupname) // sign group name
6291 {
6292 signlist_T *sign; // a sign in the signlist
6293
6294 FOR_ALL_SIGNS_IN_BUF(buf, sign)
6295 if (sign->lnum == lnum && sign_in_group(sign, groupname))
6296 return sign;
6297
6298 return NULL;
6299 }
6300
6301 /*
6302 * Return the sign with identifier 'id' in group 'group' placed in buffer 'buf'
6303 */
6304 signlist_T *
6305 buf_getsign_with_id(
6306 buf_T *buf, // buffer whose sign we are searching for
6307 int id, // sign identifier
6308 char_u *group) // sign group
6309 {
6310 signlist_T *sign; // a sign in the signlist
6311
6312 FOR_ALL_SIGNS_IN_BUF(buf, sign)
6313 if (sign->id == id && sign_in_group(sign, group))
6314 return sign;
6315
6316 return NULL;
6317 }
6318
6319 /*
6320 * Return the identifier of the sign at line number 'lnum' in buffer 'buf'.
6321 */
6322 int
6323 buf_findsign_id(
6324 buf_T *buf, // buffer whose sign we are searching for
6325 linenr_T lnum, // line number of sign
6326 char_u *groupname) // sign group name
6327 {
6328 signlist_T *sign; // a sign in the signlist
6329
6330 sign = buf_getsign_at_line(buf, lnum, groupname);
6331 if (sign != NULL)
6332 return sign->id;
6333
6334 return 0;
6335 }
6336
6337 # if defined(FEAT_NETBEANS_INTG) || defined(PROTO)
6338 /*
6339 * See if a given type of sign exists on a specific line.
6340 */
6341 int
6342 buf_findsigntype_id(
6343 buf_T *buf, /* buffer whose sign we are searching for */
6344 linenr_T lnum, /* line number of sign */
6345 int typenr) /* sign type number */
6346 {
6347 signlist_T *sign; /* a sign in the signlist */
6348
6349 FOR_ALL_SIGNS_IN_BUF(buf, sign)
6350 if (sign->lnum == lnum && sign->typenr == typenr)
6351 return sign->id;
6352
6353 return 0;
6354 }
6355
6356
6357 # if defined(FEAT_SIGN_ICONS) || defined(PROTO)
6358 /*
6359 * Return the number of icons on the given line.
6360 */
6361 int
6362 buf_signcount(buf_T *buf, linenr_T lnum)
6363 {
6364 signlist_T *sign; // a sign in the signlist
6365 int count = 0;
6366
6367 FOR_ALL_SIGNS_IN_BUF(buf, sign)
6368 if (sign->lnum == lnum)
6369 if (sign_get_image(sign->typenr) != NULL)
6370 count++;
6371
6372 return count;
6373 }
6374 # endif /* FEAT_SIGN_ICONS */
6375 # endif /* FEAT_NETBEANS_INTG */
6376
6377 /*
6378 * Delete signs in group 'group' in buffer "buf". If 'group' is '*', then
6379 * delete all the signs.
6380 */
6381 void
6382 buf_delete_signs(buf_T *buf, char_u *group)
6383 {
6384 signlist_T *sign;
6385 signlist_T **lastp; // pointer to pointer to current sign
6386 signlist_T *next;
6387
6388 // When deleting the last sign need to redraw the windows to remove the
6389 // sign column. Not when curwin is NULL (this means we're exiting).
6390 if (buf->b_signlist != NULL && curwin != NULL)
6391 {
6392 redraw_buf_later(buf, NOT_VALID);
6393 changed_cline_bef_curs();
6394 }
6395
6396 lastp = &buf->b_signlist;
6397 for (sign = buf->b_signlist; sign != NULL; sign = next)
6398 {
6399 next = sign->next;
6400 if (sign_in_group(sign, group))
6401 {
6402 *lastp = next;
6403 if (next != NULL)
6404 next->prev = sign->prev;
6405 if (sign->group != NULL)
6406 sign_group_unref(sign->group->sg_name);
6407 vim_free(sign);
6408 }
6409 else
6410 lastp = &sign->next;
6411 }
6412 }
6413
6414 /*
6415 * Delete all the signs in the specified group in all the buffers.
6416 */
6417 void
6418 buf_delete_all_signs(char_u *groupname)
6419 {
6420 buf_T *buf; /* buffer we are checking for signs */
6421
6422 FOR_ALL_BUFFERS(buf)
6423 if (buf->b_signlist != NULL)
6424 buf_delete_signs(buf, groupname);
6425 }
6426
6427 /*
6428 * List placed signs for "rbuf". If "rbuf" is NULL do it for all buffers.
6429 */
6430 void
6431 sign_list_placed(buf_T *rbuf, char_u *sign_group)
6432 {
6433 buf_T *buf;
6434 signlist_T *sign;
6435 char lbuf[BUFSIZ];
6436 char group[BUFSIZ];
6437
6438 MSG_PUTS_TITLE(_("\n--- Signs ---"));
6439 msg_putchar('\n');
6440 if (rbuf == NULL)
6441 buf = firstbuf;
6442 else
6443 buf = rbuf;
6444 while (buf != NULL && !got_int)
6445 {
6446 if (buf->b_signlist != NULL)
6447 {
6448 vim_snprintf(lbuf, BUFSIZ, _("Signs for %s:"), buf->b_fname);
6449 MSG_PUTS_ATTR(lbuf, HL_ATTR(HLF_D));
6450 msg_putchar('\n');
6451 }
6452 FOR_ALL_SIGNS_IN_BUF(buf, sign)
6453 {
6454 if (got_int)
6455 break;
6456 if (!sign_in_group(sign, sign_group))
6457 continue;
6458 if (sign->group != NULL)
6459 vim_snprintf(group, BUFSIZ, " group=%s",
6460 sign->group->sg_name);
6461 else
6462 group[0] = '\0';
6463 vim_snprintf(lbuf, BUFSIZ, _(" line=%ld id=%d%s name=%s "
6464 "priority=%d"),
6465 (long)sign->lnum, sign->id, group,
6466 sign_typenr2name(sign->typenr), sign->priority);
6467 MSG_PUTS(lbuf);
6468 msg_putchar('\n');
6469 }
6470 if (rbuf != NULL)
6471 break;
6472 buf = buf->b_next;
6473 }
6474 }
6475
6476 /*
6477 * Adjust a placed sign for inserted/deleted lines.
6478 */
6479 void
6480 sign_mark_adjust(
6481 linenr_T line1,
6482 linenr_T line2,
6483 long amount,
6484 long amount_after)
6485 {
6486 signlist_T *sign; /* a sign in a b_signlist */
6487
6488 FOR_ALL_SIGNS_IN_BUF(curbuf, sign)
6489 {
6490 if (sign->lnum >= line1 && sign->lnum <= line2)
6491 {
6492 if (amount == MAXLNUM)
6493 sign->lnum = line1;
6494 else
6495 sign->lnum += amount;
6496 }
6497 else if (sign->lnum > line2)
6498 sign->lnum += amount_after;
6499 }
6500 }
6501 #endif /* FEAT_SIGNS */
6502
6503 /* 5867 /*
6504 * Set 'buflisted' for curbuf to "on" and trigger autocommands if it changed. 5868 * Set 'buflisted' for curbuf to "on" and trigger autocommands if it changed.
6505 */ 5869 */
6506 void 5870 void
6507 set_buflisted(int on) 5871 set_buflisted(int on)