mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	Add comments to build_stl_str_hl
This commit is contained in:
		| @@ -2833,8 +2833,11 @@ build_stl_str_hl ( | ||||
| { | ||||
|   int groupitem[STL_MAX_ITEM]; | ||||
|   struct stl_item { | ||||
|     // Where the item starts in the status line output buffer | ||||
|     char_u          *start; | ||||
|     // The minimum width of the item (at most 50 characters) | ||||
|     int minwid; | ||||
|     // The maximum width of the item | ||||
|     int maxwid; | ||||
|     enum { | ||||
|       Normal, | ||||
| @@ -2846,6 +2849,13 @@ build_stl_str_hl ( | ||||
|       Trunc | ||||
|     }               type; | ||||
|   }           item[STL_MAX_ITEM]; | ||||
|  | ||||
|   enum number_base { | ||||
|      DECIMAL     = 10, | ||||
|      OCTAL       = 8, | ||||
|      HEXIDECIMAL = 16 | ||||
|   }; | ||||
|  | ||||
| #define TMPLEN 70 | ||||
|   char_u tmp[TMPLEN]; | ||||
|   char_u      *usefmt = fmt; | ||||
| @@ -2879,12 +2889,18 @@ build_stl_str_hl ( | ||||
|     byteval = (*mb_ptr2char)(line_ptr + wp->w_cursor.col); | ||||
|  | ||||
|   int groupdepth = 0; | ||||
|   char_u *p = out; | ||||
|  | ||||
|   int curitem = 0; | ||||
|   bool prevchar_isflag = true; | ||||
|   bool prevchar_isitem = false; | ||||
|   char_u *s; | ||||
|   for (s = usefmt; *s; ) { | ||||
|  | ||||
|   // p is the current position in the output buffer | ||||
|   char_u *p = out; | ||||
|  | ||||
|  | ||||
|   // Proceed character by character through the statusline format string | ||||
|   // s is the current positon in the input buffer | ||||
|   for (char_u *s = usefmt; *s; ) { | ||||
|     if (curitem == STL_MAX_ITEM) { | ||||
|       /* There are too many items.  Add the error code to the statusline | ||||
|        * to give the user a hint about what went wrong. */ | ||||
| @@ -2898,64 +2914,99 @@ build_stl_str_hl ( | ||||
|     if (*s != NUL && *s != '%') | ||||
|       prevchar_isflag = prevchar_isitem = false; | ||||
|  | ||||
|     /* | ||||
|      * Handle up to the next '%' or the end. | ||||
|      */ | ||||
|     // Copy the formatting verbatim until we reach the end of the string | ||||
|     // or find a formatting item (denoted by `%`) | ||||
|     // or run out of room in our output buffer. | ||||
|     while (*s != NUL && *s != '%' && p + 1 < out + outlen) | ||||
|       *p++ = *s++; | ||||
|  | ||||
|     // If we have processed the entire format string or run out of | ||||
|     // room in our output buffer, exit the loop. | ||||
|     if (*s == NUL || p + 1 >= out + outlen) | ||||
|       break; | ||||
|  | ||||
|     /* | ||||
|      * Handle one '%' item. | ||||
|      */ | ||||
|     // The rest of this loop wil handle a single `%` item. | ||||
|     // Note: We increment here to skip over the `%` character we are currently | ||||
|     //       on so we can process the item's contents. | ||||
|     s++; | ||||
|     if (*s == NUL)      /* ignore trailing % */ | ||||
|  | ||||
|     // Ignore `%` at the end of the format string | ||||
|     if (*s == NUL) { | ||||
|       break; | ||||
|     } | ||||
|  | ||||
|     // Two `%` in a row is the escape sequence to print a | ||||
|     // single `%` in the output buffer. | ||||
|     if (*s == '%') { | ||||
|       // Ignore the character if we're out of room in the output buffer. | ||||
|       if (p + 1 >= out + outlen) | ||||
|         break; | ||||
|       *p++ = *s++; | ||||
|       prevchar_isflag = prevchar_isitem = false; | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
|     // STL_MIDDLEMARK denotes the separation place between left and right aligned items. | ||||
|     if (*s == STL_MIDDLEMARK) { | ||||
|       s++; | ||||
|       if (groupdepth > 0) | ||||
|       // Ignored when we are inside of a grouping | ||||
|       if (groupdepth > 0) { | ||||
|         continue; | ||||
|       } | ||||
|       item[curitem].type = Middle; | ||||
|       item[curitem++].start = p; | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
|     // STL_TRUNCMARK denotes where to begin truncating if the statusline is too long. | ||||
|     if (*s == STL_TRUNCMARK) { | ||||
|       s++; | ||||
|       item[curitem].type = Trunc; | ||||
|       item[curitem++].start = p; | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
|     // The end of a grouping | ||||
|     if (*s == ')') { | ||||
|       s++; | ||||
|       if (groupdepth < 1) | ||||
|       // Ignore if we are not actually inside a group currently | ||||
|       if (groupdepth < 1) { | ||||
|         continue; | ||||
|       } | ||||
|       groupdepth--; | ||||
|  | ||||
|       //{ Determine how long the group is. | ||||
|       //  Note: We set the current output position to null so `vim_strsize` will work. | ||||
|       char_u *t = item[groupitem[groupdepth]].start; | ||||
|       *p = NUL; | ||||
|       long l = vim_strsize(t); | ||||
|       //} | ||||
|  | ||||
|       // If the group contained internal items and the group did not have a minimum width, | ||||
|       // and if there were no normal items in the group, | ||||
|       // move the output pointer back to where the group started (erase the group). | ||||
|       // Note: This also erases any plaintext characters that were in the group. | ||||
|       //       Otherwise there would be no reason to do this step. | ||||
|       if (curitem > groupitem[groupdepth] + 1 | ||||
|           && item[groupitem[groupdepth]].minwid == 0) { | ||||
|         /* remove group if all items are empty */ | ||||
|         long n; | ||||
|         for (n = groupitem[groupdepth] + 1; n < curitem; n++) | ||||
|           if (item[n].type == Normal) | ||||
|         bool has_normal_items = false; | ||||
|         for (long n = groupitem[groupdepth] + 1; n < curitem; n++) { | ||||
|           if (item[n].type == Normal) { | ||||
|             has_normal_items = true; | ||||
|             break; | ||||
|         if (n == curitem) { | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         if (!has_normal_items) { | ||||
|           p = t; | ||||
|           l = 0; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       // If the group is longer than it is allowed to be | ||||
|       // truncate by removing bytes from the start of the group text. | ||||
|       if (l > item[groupitem[groupdepth]].maxwid) { | ||||
|         /* truncate, remove n bytes of text at the start */ | ||||
|         //{ Determine the number of bytes to remove | ||||
|         long n; | ||||
|         if (has_mbyte) { | ||||
|           /* Find the first character that should be included. */ | ||||
| @@ -2966,60 +3017,88 @@ build_stl_str_hl ( | ||||
|           } | ||||
|         } else | ||||
|           n = (long)(p - t) - item[groupitem[groupdepth]].maxwid + 1; | ||||
|         //} | ||||
|  | ||||
|         // Prepend the `<` to indicate that the output was truncated. | ||||
|         *t = '<'; | ||||
|  | ||||
|         //{ Move the truncated output | ||||
|         memmove(t + 1, t + n, (size_t)(p - (t + n))); | ||||
|         p = p - n + 1; | ||||
|         /* Fill up space left over by half a double-wide char. */ | ||||
|         while (++l < item[groupitem[groupdepth]].minwid) | ||||
|           *p++ = fillchar; | ||||
|         //} | ||||
|  | ||||
|         /* correct the start of the items for the truncation */ | ||||
|         for (l = groupitem[groupdepth] + 1; l < curitem; l++) { | ||||
|           // Shift everything back by the number of removed bytes | ||||
|           item[l].start -= n; | ||||
|  | ||||
|           // If the item was partially or completely truncated, set its | ||||
|           // start to the start of the group | ||||
|           if (item[l].start < t) | ||||
|             item[l].start = t; | ||||
|         } | ||||
|       // If the group is shorter than the minimum width, add padding characters. | ||||
|       } else if (abs(item[groupitem[groupdepth]].minwid) > l) { | ||||
|         /* fill */ | ||||
|         long n = item[groupitem[groupdepth]].minwid; | ||||
|         if (n < 0) { | ||||
|           /* fill by appending characters */ | ||||
|           n = 0 - n; | ||||
|           while (l++ < n && p + 1 < out + outlen) | ||||
|         long min_group_width = item[groupitem[groupdepth]].minwid; | ||||
|         // If the group is left-aligned, add characters to the right. | ||||
|         if (min_group_width < 0) { | ||||
|           min_group_width = 0 - min_group_width; | ||||
|           while (l++ < min_group_width && p + 1 < out + outlen) | ||||
|             *p++ = fillchar; | ||||
|         // If the group is right-aligned, shift everything to the right and | ||||
|         // prepend with filler characters. | ||||
|         } else { | ||||
|           /* fill by inserting characters */ | ||||
|           memmove(t + n - l, t, (size_t)(p - t)); | ||||
|           l = n - l; | ||||
|           if (p + l >= out + outlen) | ||||
|           //{ Move the group to the right | ||||
|           memmove(t + min_group_width - l, t, (size_t)(p - t)); | ||||
|           l = min_group_width - l; | ||||
|           if (p + l >= out + outlen) { | ||||
|             l = (long)((out + outlen) - p - 1); | ||||
|           } | ||||
|           p += l; | ||||
|           for (n = groupitem[groupdepth] + 1; n < curitem; n++) | ||||
|           //} | ||||
|  | ||||
|           // Adjust item start positions | ||||
|           for (int n = groupitem[groupdepth] + 1; n < curitem; n++) { | ||||
|             item[n].start += l; | ||||
|           for (; l > 0; l--) | ||||
|           } | ||||
|  | ||||
|           // Prepend the fill characters | ||||
|           for (; l > 0; l--) { | ||||
|             *t++ = fillchar; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|       continue; | ||||
|     } | ||||
|     int minwid = 0; | ||||
|     int maxwid = 9999; | ||||
|     bool zeropad = false; | ||||
|     long l = 1; | ||||
|     if (*s == '0') { | ||||
|     bool left_align = false; | ||||
|  | ||||
|     // Denotes that numbers should be left-padded with zeros | ||||
|     bool zeropad = (*s == '0'); | ||||
|     if (zeropad) { | ||||
|       s++; | ||||
|       zeropad = true; | ||||
|     } | ||||
|  | ||||
|     // Denotes that the item should be left-aligned. | ||||
|     // This is tracked by using a negative length. | ||||
|     if (*s == '-') { | ||||
|       s++; | ||||
|       l = -1; | ||||
|       left_align = true; | ||||
|     } | ||||
|  | ||||
|     // The first digit group is the item's min width | ||||
|     if (ascii_isdigit(*s)) { | ||||
|       minwid = getdigits_int(&s); | ||||
|       if (minwid < 0)           /* overflow */ | ||||
|         minwid = 0; | ||||
|     } | ||||
|  | ||||
|     // User highlight groups override the min width field | ||||
|     // to denote the styling to use. | ||||
|     if (*s == STL_USER_HL) { | ||||
|       item[curitem].type = Highlight; | ||||
|       item[curitem].start = p; | ||||
| @@ -3049,6 +3128,9 @@ build_stl_str_hl ( | ||||
|       curitem++; | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
|     // Denotes the end of the minwid | ||||
|     // the maxwid may follow immediately after | ||||
|     if (*s == '.') { | ||||
|       s++; | ||||
|       if (ascii_isdigit(*s)) { | ||||
| @@ -3057,7 +3139,12 @@ build_stl_str_hl ( | ||||
|           maxwid = 50; | ||||
|       } | ||||
|     } | ||||
|     minwid = (minwid > 50 ? 50 : minwid) * l; | ||||
|  | ||||
|     // Bound the minimum width at 50. | ||||
|     // Make the number negative to denote left alignment of the item | ||||
|     minwid = (minwid > 50 ? 50 : minwid) * (left_align ? -1 : 1); | ||||
|  | ||||
|     // Denotes the start of a new group | ||||
|     if (*s == '(') { | ||||
|       groupitem[groupdepth++] = curitem; | ||||
|       item[curitem].type = Group; | ||||
| @@ -3068,14 +3155,19 @@ build_stl_str_hl ( | ||||
|       curitem++; | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
|     // An invalid item was specified. | ||||
|     // Continue processing on the next character of the format string. | ||||
|     if (vim_strchr(STL_ALL, *s) == NULL) { | ||||
|       s++; | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
|     // The status line item type | ||||
|     char_u opt = *s++; | ||||
|  | ||||
|     /* OK - now for the real work */ | ||||
|     char_u base = 'D'; | ||||
|     enum number_base base = DECIMAL; | ||||
|     bool itemisflag = false; | ||||
|     bool fillable = true; | ||||
|     long num = -1; | ||||
| @@ -3103,6 +3195,9 @@ build_stl_str_hl ( | ||||
|     case STL_VIM_EXPR:     /* '{' */ | ||||
|     { | ||||
|       itemisflag = true; | ||||
|  | ||||
|       // Attempt to copy the expression to evaluate into | ||||
|       // the output buffer as a null-terminated string. | ||||
|       char_u *t = p; | ||||
|       while (*s != '}' && *s != NUL && p + 1 < out + outlen) | ||||
|         *p++ = *s++; | ||||
| @@ -3110,22 +3205,37 @@ build_stl_str_hl ( | ||||
|         break; | ||||
|       s++; | ||||
|       *p = 0; | ||||
|  | ||||
|       // Move our position in the output buffer to the beginning of the expression | ||||
|       p = t; | ||||
|  | ||||
|       //{ Evaluate the expression | ||||
|  | ||||
|       // Store the current buffer number as a string variable | ||||
|       vim_snprintf((char *)tmp, sizeof(tmp), "%d", curbuf->b_fnum); | ||||
|       set_internal_string_var((char_u *)"actual_curbuf", tmp); | ||||
|  | ||||
|       // Switch the curbuf and curwin to the buffer and window we are evaluating the | ||||
|       // statusline for. | ||||
|       buf_T *o_curbuf = curbuf; | ||||
|       win_T *o_curwin = curwin; | ||||
|       curwin = wp; | ||||
|       curbuf = wp->w_buffer; | ||||
|  | ||||
|       // Note: The result stored in `t` is unused. | ||||
|       str = eval_to_string_safe(p, &t, use_sandbox); | ||||
|  | ||||
|       // Switch back to the actual current buffer and window. | ||||
|       curwin = o_curwin; | ||||
|       curbuf = o_curbuf; | ||||
|  | ||||
|       // Remove the variable we just stored | ||||
|       do_unlet((char_u *)"g:actual_curbuf", TRUE); | ||||
|  | ||||
|       //} | ||||
|  | ||||
|       // Check if the evaluated result is a number. | ||||
|       // If so, convert the number to an int and free the string. | ||||
|       if (str != NULL && *str != 0) { | ||||
|         if (*skipdigits(str) == NUL) { | ||||
|           num = atoi((char *)str); | ||||
| @@ -3176,15 +3286,27 @@ build_stl_str_hl ( | ||||
|       break; | ||||
|  | ||||
|     case STL_ALTPERCENT: | ||||
|       // Store the position percentage in our temporary buffer. | ||||
|       // Note: We cannot store the value in `num` because | ||||
|       //       `get_rel_pos` can return a named position. Ex: "Top" | ||||
|       get_rel_pos(wp, tmp, TMPLEN); | ||||
|       str = tmp; | ||||
|       get_rel_pos(wp, str, TMPLEN); | ||||
|       break; | ||||
|  | ||||
|     case STL_ARGLISTSTAT: | ||||
|       fillable = false; | ||||
|  | ||||
|       // Note: This is important because `append_arg_number` starts appending | ||||
|       //       at the end of the null-terminated string. | ||||
|       //       Setting the first byte to null means it will place the argument | ||||
|       //       number string at the beginning of the buffer. | ||||
|       tmp[0] = 0; | ||||
|       if (append_arg_number(wp, tmp, (int)sizeof(tmp), FALSE)) | ||||
|  | ||||
|       // Note: The call will only return true if it actually | ||||
|       //       appended data to the `tmp` buffer. | ||||
|       if (append_arg_number(wp, tmp, (int)sizeof(tmp), FALSE)) { | ||||
|         str = tmp; | ||||
|       } | ||||
|       break; | ||||
|  | ||||
|     case STL_KEYMAP: | ||||
| @@ -3201,16 +3323,17 @@ build_stl_str_hl ( | ||||
|       break; | ||||
|  | ||||
|     case STL_OFFSET_X: | ||||
|       base = 'X'; | ||||
|       base = HEXIDECIMAL; | ||||
|     case STL_OFFSET: | ||||
|       l = ml_find_line_or_offset(wp->w_buffer, wp->w_cursor.lnum, NULL); | ||||
|     { | ||||
|       long l = ml_find_line_or_offset(wp->w_buffer, wp->w_cursor.lnum, NULL); | ||||
|       num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) || l < 0 ? | ||||
|             0L : l + 1 + (!(State & INSERT) && empty_line ? | ||||
|                           0 : (int)wp->w_cursor.col); | ||||
|       break; | ||||
|  | ||||
|     } | ||||
|     case STL_BYTEVAL_X: | ||||
|       base = 'X'; | ||||
|       base = HEXIDECIMAL; | ||||
|     case STL_BYTEVAL: | ||||
|       num = byteval; | ||||
|       if (num == NL) | ||||
| @@ -3235,6 +3358,8 @@ build_stl_str_hl ( | ||||
|       break; | ||||
|  | ||||
|     case STL_FILETYPE: | ||||
|       // Copy the filetype if it is not null and the formatted string will fit | ||||
|       // in the temporary buffer (including the brackets and null terminating character) | ||||
|       if (*wp->w_buffer->b_p_ft != NUL | ||||
|           && STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 3) { | ||||
|         vim_snprintf((char *)tmp, sizeof(tmp), "[%s]", | ||||
| @@ -3246,12 +3371,16 @@ build_stl_str_hl ( | ||||
|     case STL_FILETYPE_ALT: | ||||
|     { | ||||
|       itemisflag = true; | ||||
|       // Copy the filetype if it is not null and the formatted string will fit | ||||
|       // in the temporary buffer (including the comma and null terminating character) | ||||
|       if (*wp->w_buffer->b_p_ft != NUL | ||||
|           && STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 2) { | ||||
|         vim_snprintf((char *)tmp, sizeof(tmp), ",%s", | ||||
|             wp->w_buffer->b_p_ft); | ||||
|         for (char_u *t = tmp; *t != 0; t++) | ||||
|         // Uppercase the file extension | ||||
|         for (char_u *t = tmp; *t != 0; t++) { | ||||
|           *t = TOUPPER_LOC(*t); | ||||
|         } | ||||
|         str = tmp; | ||||
|       } | ||||
|       break; | ||||
| @@ -3288,24 +3417,35 @@ build_stl_str_hl ( | ||||
|  | ||||
|     case STL_HIGHLIGHT: | ||||
|     { | ||||
|       //{ The name of the highlight is surrounded by `#` | ||||
|       char_u *t = s; | ||||
|       while (*s != '#' && *s != NUL) | ||||
|       while (*s != '#' && *s != NUL) { | ||||
|         ++s; | ||||
|       } | ||||
|       //} | ||||
|  | ||||
|       // Create a highlight item based on the name | ||||
|       if (*s == '#') { | ||||
|         item[curitem].type = Highlight; | ||||
|         item[curitem].start = p; | ||||
|         item[curitem].minwid = -syn_namen2id(t, (int)(s - t)); | ||||
|         curitem++; | ||||
|         s++; | ||||
|       } | ||||
|       if (*s != NUL) | ||||
|         ++s; | ||||
|       continue; | ||||
|     } | ||||
|     } | ||||
|  | ||||
|     // If we made it this far, the item is normal and starts at | ||||
|     // our current position in the output buffer. | ||||
|     // Non-normal items would have `continued`. | ||||
|     item[curitem].start = p; | ||||
|     item[curitem].type = Normal; | ||||
|  | ||||
|     // Copy the item string into the output buffer | ||||
|     if (str != NULL && *str) { | ||||
|       //{ Skip the leading `,` or ` ` if the item is a flag | ||||
|       //  and the proper conditions are met | ||||
|       char_u *t = str; | ||||
|       if (itemisflag) { | ||||
|         if ((t[0] && t[1]) | ||||
| @@ -3314,20 +3454,35 @@ build_stl_str_hl ( | ||||
|           t++; | ||||
|         prevchar_isflag = true; | ||||
|       } | ||||
|       l = vim_strsize(t); | ||||
|       if (l > 0) | ||||
|       //} | ||||
|  | ||||
|       long l = vim_strsize(t); | ||||
|  | ||||
|       // If this item is non-empty, record that the last thing | ||||
|       // we put in the output buffer was an item | ||||
|       if (l > 0) { | ||||
|         prevchar_isitem = true; | ||||
|       } | ||||
|  | ||||
|       // If the item is too wide, truncate it from the beginning | ||||
|       if (l > maxwid) { | ||||
|         while (l >= maxwid) | ||||
|           if (has_mbyte) { | ||||
|             l -= ptr2cells(t); | ||||
|             t += (*mb_ptr2len)(t); | ||||
|           } else | ||||
|           } else { | ||||
|             l -= byte2cells(*t++); | ||||
|           } | ||||
|  | ||||
|         // Early out if there isn't enough room for the truncation marker | ||||
|         if (p + 1 >= out + outlen) | ||||
|           break; | ||||
|  | ||||
|         // Add the truncation marker | ||||
|         *p++ = '<'; | ||||
|       } | ||||
|  | ||||
|       // If the item is right aligned and not wide enough, pad with fill characters. | ||||
|       if (minwid > 0) { | ||||
|         for (; l < minwid && p + 1 < out + outlen; l++) { | ||||
|           /* Don't put a "-" in front of a digit. */ | ||||
| @@ -3337,8 +3492,13 @@ build_stl_str_hl ( | ||||
|             *p++ = fillchar; | ||||
|         } | ||||
|         minwid = 0; | ||||
|       } else | ||||
|       } else { | ||||
|         // Note: The negative value denotes a left aligned item. | ||||
|         //       Here we switch the minimum width back to a positive value. | ||||
|         minwid *= -1; | ||||
|       } | ||||
|  | ||||
|       //{ Copy the string text into the output buffer | ||||
|       while (*t && p + 1 < out + outlen) { | ||||
|         *p++ = *t++; | ||||
|         /* Change a space by fillchar, unless fillchar is '-' and a | ||||
| @@ -3347,151 +3507,256 @@ build_stl_str_hl ( | ||||
|             && (!ascii_isdigit(*t) || fillchar != '-')) | ||||
|           p[-1] = fillchar; | ||||
|       } | ||||
|       for (; l < minwid && p + 1 < out + outlen; l++) | ||||
|         *p++ = fillchar; | ||||
|     } else if (num >= 0) { | ||||
|       int nbase = (base == 'D' ? 10 : (base == 'O' ? 8 : 16)); | ||||
|       char_u nstr[20]; | ||||
|       //} | ||||
|  | ||||
|       // For left-aligned items, fill any remaining space with the fillchar | ||||
|       for (; l < minwid && p + 1 < out + outlen; l++) { | ||||
|         *p++ = fillchar; | ||||
|       } | ||||
|  | ||||
|     // Otherwise if the item is a number, copy that to the output buffer. | ||||
|     } else if (num >= 0) { | ||||
|       if (p + 20 >= out + outlen) | ||||
|         break;                  /* not sufficient space */ | ||||
|       prevchar_isitem = true; | ||||
|  | ||||
|       //{ Build the formatting string | ||||
|       char_u nstr[20]; | ||||
|       char_u *t = nstr; | ||||
|       if (opt == STL_VIRTCOL_ALT) { | ||||
|         *t++ = '-'; | ||||
|         minwid--; | ||||
|       } | ||||
|       *t++ = '%'; | ||||
|       if (zeropad) | ||||
|       if (zeropad) { | ||||
|         *t++ = '0'; | ||||
|       *t++ = '*'; | ||||
|       *t++ = nbase == 16 ? base : (char_u)(nbase == 8 ? 'o' : 'd'); | ||||
|       *t = 0; | ||||
|       } | ||||
|  | ||||
|       long n; | ||||
|       for (n = num, l = 1; n >= nbase; n /= nbase) | ||||
|       // Note: The `*` means we take the width as one of the arguments | ||||
|       *t++ = '*'; | ||||
|       *t++ = (char_u) (base == HEXIDECIMAL ? 'X' : (base == OCTAL ? 'o' : 'd')); | ||||
|       *t = 0; | ||||
|       //} | ||||
|  | ||||
|       //{ Determine how many characters the number will take up when printed | ||||
|       long l; | ||||
|       for (long n = num, l = 1; n >= base; n /= base) { | ||||
|         l++; | ||||
|       if (opt == STL_VIRTCOL_ALT) | ||||
|       } | ||||
|  | ||||
|       // VIRTCOL_ALT takes up an extra character because of the `-` we added above. | ||||
|       if (opt == STL_VIRTCOL_ALT) { | ||||
|         l++; | ||||
|       } | ||||
|       //} | ||||
|  | ||||
|       size_t remaining_buf_len = (outlen - (p - out)); | ||||
|  | ||||
|       // If the number is going to take up too much room | ||||
|       // Figure out the approximate number in "scientific" type notation. | ||||
|       // Ex: 14532 with maxwid of 4 -> '14>3' | ||||
|       if (l > maxwid) { | ||||
|         // Add two to the width because the power piece will take two extra characters | ||||
|         l += 2; | ||||
|         n = l - maxwid; | ||||
|         while (l-- > maxwid) | ||||
|           num /= nbase; | ||||
|  | ||||
|         // How many extra characters there are | ||||
|         long n = l - maxwid; | ||||
|  | ||||
|         //{ Reduce the number by base^n | ||||
|         while (l-- > maxwid) { | ||||
|           num /= base; | ||||
|         } | ||||
|         //} | ||||
|  | ||||
|         //{ Add the format string for the exponent bit | ||||
|         *t++ = '>'; | ||||
|         *t++ = '%'; | ||||
|         // Use the same base as the first number | ||||
|         *t = t[-3]; | ||||
|         *++t = 0; | ||||
|         vim_snprintf((char *)p, outlen - (p - out), (char *)nstr, | ||||
|             0, num, n); | ||||
|       } else | ||||
|         vim_snprintf((char *)p, outlen - (p - out), (char *)nstr, | ||||
|             minwid, num); | ||||
|       p += STRLEN(p); | ||||
|     } else | ||||
|       item[curitem].type = Empty; | ||||
|         //} | ||||
|  | ||||
|     if (opt == STL_VIM_EXPR) | ||||
|         vim_snprintf((char *)p, remaining_buf_len, (char *)nstr, | ||||
|             0, num, n); | ||||
|       } else { | ||||
|         vim_snprintf((char *)p, remaining_buf_len, (char *)nstr, | ||||
|             minwid, num); | ||||
|       } | ||||
|  | ||||
|       // Advance the output buffer position to the end of the number we just printed | ||||
|       p += STRLEN(p); | ||||
|  | ||||
|     // Otherwise, there was nothing to print so mark the item as empty | ||||
|     } else { | ||||
|       item[curitem].type = Empty; | ||||
|     } | ||||
|  | ||||
|     // Free the string buffer if we allocated it. | ||||
|     // Note: This is not needed if `str` is pointing at `tmp` | ||||
|     if (opt == STL_VIM_EXPR) { | ||||
|       xfree(str); | ||||
|     } | ||||
|  | ||||
|     if (num >= 0 || (!itemisflag && str && *str)) | ||||
|       prevchar_isflag = false;              /* Item not NULL, but not a flag */ | ||||
|  | ||||
|     // Item processed, move to the next | ||||
|     curitem++; | ||||
|   } | ||||
|  | ||||
|   // Null terminate the output buffer | ||||
|   *p = NUL; | ||||
|   int itemcnt = curitem; | ||||
|  | ||||
|   if (usefmt != fmt) | ||||
|   // Free the format buffer if we allocated it internally | ||||
|   if (usefmt != fmt) { | ||||
|     xfree(usefmt); | ||||
|   } | ||||
|  | ||||
|   int width = vim_strsize(out); | ||||
|   if (maxwidth > 0 && width > maxwidth) { | ||||
|     /* Result is too long, must truncate somewhere. */ | ||||
|     long l = 0; | ||||
|     if (itemcnt == 0) | ||||
|       s = out; | ||||
|     else { | ||||
|       for (; l < itemcnt; l++) | ||||
|         if (item[l].type == Trunc) { | ||||
|           /* Truncate at %< item. */ | ||||
|           s = item[l].start; | ||||
|     int item_idx = 0; | ||||
|     char_u *trunc_p; | ||||
|  | ||||
|     // If there are no items, truncate from beginning | ||||
|     if (itemcnt == 0) { | ||||
|       trunc_p = out; | ||||
|  | ||||
|     // Otherwise, look for the truncation item | ||||
|     } else { | ||||
|       // Default to truncating at the first item | ||||
|       trunc_p = item[0].start; | ||||
|       item_idx = 0; | ||||
|  | ||||
|       for (int i; i < itemcnt; i++) | ||||
|         if (item[i].type == Trunc) { | ||||
|           // Truncate at %< item. | ||||
|           trunc_p = item[i].start; | ||||
|           item_idx = i; | ||||
|           break; | ||||
|         } | ||||
|       if (l == itemcnt) { | ||||
|         /* No %< item, truncate first item. */ | ||||
|         s = item[0].start; | ||||
|         l = 0; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     if (width - vim_strsize(s) >= maxwidth) { | ||||
|       /* Truncation mark is beyond max length */ | ||||
|     // If the truncation point we found is beyond the maximum | ||||
|     // length of the string, truncate the end of the string. | ||||
|     if (width - vim_strsize(trunc_p) >= maxwidth) { | ||||
|       // If we are using a multi-byte encoding, walk from the beginning of the | ||||
|       // string to find the last character that will fit. | ||||
|       if (has_mbyte) { | ||||
|         s = out; | ||||
|         trunc_p = out; | ||||
|         width = 0; | ||||
|         for (;; ) { | ||||
|           width += ptr2cells(s); | ||||
|           width += ptr2cells(trunc_p); | ||||
|           if (width >= maxwidth) | ||||
|             break; | ||||
|           s += (*mb_ptr2len)(s); | ||||
|  | ||||
|           // Note: Only advance the pointer if the next | ||||
|           //       character will fit in the available output space | ||||
|           trunc_p += (*mb_ptr2len)(trunc_p); | ||||
|         } | ||||
|         /* Fill up for half a double-wide character. */ | ||||
|         while (++width < maxwidth) | ||||
|           *s++ = fillchar; | ||||
|       } else | ||||
|         s = out + maxwidth - 1; | ||||
|       for (l = 0; l < itemcnt; l++) | ||||
|         if (item[l].start > s) | ||||
|           break; | ||||
|       itemcnt = l; | ||||
|       *s++ = '>'; | ||||
|       *s = 0; | ||||
|     } else { | ||||
|       long n; | ||||
|       if (has_mbyte) { | ||||
|         n = 0; | ||||
|         while (width >= maxwidth) { | ||||
|           width -= ptr2cells(s + n); | ||||
|           n += (*mb_ptr2len)(s + n); | ||||
|         // XXX : This seems impossible given the exit condition above? | ||||
|         while (++width < maxwidth) { | ||||
|           *trunc_p++ = fillchar; | ||||
|         } | ||||
|       } else | ||||
|         n = width - maxwidth + 1; | ||||
|       p = s + n; | ||||
|       STRMOVE(s + 1, p); | ||||
|       *s = '<'; | ||||
|  | ||||
|       // Otherwise put the truncation point at the end, leaving enough room | ||||
|       // for a single-character truncation marker | ||||
|       } else { | ||||
|         trunc_p = out + maxwidth - 1; | ||||
|       } | ||||
|  | ||||
|       // Ignore any items in the statusline that occur after | ||||
|       // the truncation point | ||||
|       for (int i = 0; i < itemcnt; i++) { | ||||
|         if (item[i].start > trunc_p) { | ||||
|           itemcnt = i; | ||||
|           break; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       // Truncate the output | ||||
|       *trunc_p++ = '>'; | ||||
|       *trunc_p = 0; | ||||
|  | ||||
|     // Truncate at the truncation point we found | ||||
|     } else { | ||||
|       //{ Determine how many bytes to remove | ||||
|       long trunc_len; | ||||
|       if (has_mbyte) { | ||||
|         trunc_len = 0; | ||||
|         while (width >= maxwidth) { | ||||
|           width     -= ptr2cells(trunc_p + trunc_len); | ||||
|           trunc_len += (*mb_ptr2len)(trunc_p + trunc_len); | ||||
|         } | ||||
|       } else { | ||||
|         // Truncate an extra character so we can insert our `<`. | ||||
|         trunc_len = (width - maxwidth) + 1; | ||||
|       } | ||||
|       //} | ||||
|  | ||||
|       //{ Truncate the string | ||||
|       char_u *trunc_end_p = trunc_p + trunc_len; | ||||
|       STRMOVE(trunc_p + 1, trunc_end_p); | ||||
|  | ||||
|       // Put a `<` to mark where we truncated at | ||||
|       *trunc_p = '<'; | ||||
|  | ||||
|       // Advance the pointer to the end of the string | ||||
|       trunc_p = trunc_p + STRLEN(trunc_p); | ||||
|  | ||||
|       /* Fill up for half a double-wide character. */ | ||||
|       while (++width < maxwidth) { | ||||
|         s = s + STRLEN(s); | ||||
|         *s++ = fillchar; | ||||
|         *s = NUL; | ||||
|         *trunc_p++ = fillchar; | ||||
|         *trunc_p = NUL; | ||||
|       } | ||||
|       //} | ||||
|  | ||||
|       --n;              /* count the '<' */ | ||||
|       for (; l < itemcnt; l++) { | ||||
|         if (item[l].start - n >= s) | ||||
|           item[l].start -= n; | ||||
|         else | ||||
|           item[l].start = s; | ||||
|       //{ Change the start point for items based on | ||||
|       //  their position relative to our truncation point | ||||
|  | ||||
|       // Note: The offset is one less than the truncation length because | ||||
|       //       the truncation marker `<` is not counted. | ||||
|       long item_offset = trunc_len - 1; | ||||
|  | ||||
|       for (int i = item_idx; i < itemcnt; i++) { | ||||
|         // Items starting at or after the end of the truncated section need | ||||
|         // to be moved backwards. | ||||
|         if (item[i].start >= trunc_end_p) { | ||||
|           item[i].start -= item_offset; | ||||
|         // Anything inside the truncated area is set to start at the `<` truncation character. | ||||
|         } else { | ||||
|           item[i].start = trunc_p; | ||||
|         } | ||||
|       } | ||||
|       //} | ||||
|     } | ||||
|     width = maxwidth; | ||||
|   } else if (width < maxwidth && STRLEN(out) + maxwidth - width + 1 < | ||||
|              outlen) { | ||||
|     /* Apply STL_MIDDLE if any */ | ||||
|     for (long l = 0; l < itemcnt; l++) | ||||
|       if (item[l].type == Middle) { | ||||
|         p = item[l].start + maxwidth - width; | ||||
|         STRMOVE(p, item[l].start); | ||||
|         for (s = item[l].start; s < p; s++) | ||||
|  | ||||
|   // If there is room left in our statusline, and room left in our buffer, | ||||
|   // add characters at the middle marker (if there is one) to fill up the available space. | ||||
|   } else if (width < maxwidth | ||||
|                && STRLEN(out) + maxwidth - width + 1 < outlen) { | ||||
|     for (int item_idx = 0; item_idx < itemcnt; item_idx++) { | ||||
|       if (item[item_idx].type == Middle) { | ||||
|         // Move the statusline to make room for the middle characters | ||||
|         char_u *middle_end = item[item_idx].start + (maxwidth - width); | ||||
|         STRMOVE(middle_end, item[item_idx].start); | ||||
|  | ||||
|         // Fill the middle section with our fill character | ||||
|         for (char_u *s = item[item_idx].start; s < middle_end; s++) | ||||
|           *s = fillchar; | ||||
|         for (l++; l < itemcnt; l++) | ||||
|           item[l].start += maxwidth - width; | ||||
|         width = maxwidth; | ||||
|  | ||||
|         // Adjust the offset of any items after the middle | ||||
|         for (item_idx++; item_idx < itemcnt; item_idx++) | ||||
|           item[item_idx].start += maxwidth - width; | ||||
|  | ||||
|         width = maxwidth; | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /* Store the info about highlighting. */ | ||||
|   if (hltab != NULL) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Wayne Rowcliffe
					Wayne Rowcliffe