Mercurial > vim
comparison src/textprop.c @ 26242:685206b54ecf v8.2.3652
patch 8.2.3652: can only get text properties one line at a time
Commit: https://github.com/vim/vim/commit/e021662f39b38ef7cf27e13850d0ce6890e48376
Author: Yegappan Lakshmanan <yegappan@yahoo.com>
Date: Tue Nov 23 11:46:32 2021 +0000
patch 8.2.3652: can only get text properties one line at a time
Problem: Can only get text properties one line at a time.
Solution: Add options to prop_list() to use a range of lines and filter by
types. (Yegappan Lakshmanan, closes #9138)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Tue, 23 Nov 2021 13:00:05 +0100 |
parents | 78ef12e0ce8c |
children | 2df40c348c70 |
comparison
equal
deleted
inserted
replaced
26241:ae5abfa1efc8 | 26242:685206b54ecf |
---|---|
895 col = dir < 0 ? buf->b_ml.ml_line_len : 1; | 895 col = dir < 0 ? buf->b_ml.ml_line_len : 1; |
896 } | 896 } |
897 } | 897 } |
898 | 898 |
899 /* | 899 /* |
900 * Returns TRUE if 'type_or_id' is in the 'types_or_ids' list. | |
901 */ | |
902 static int | |
903 prop_type_or_id_in_list(int *types_or_ids, int len, int type_or_id) | |
904 { | |
905 int i; | |
906 | |
907 for (i = 0; i < len; i++) | |
908 if (types_or_ids[i] == type_or_id) | |
909 return TRUE; | |
910 | |
911 return FALSE; | |
912 } | |
913 | |
914 /* | |
915 * Return all the text properties in line 'lnum' in buffer 'buf' in 'retlist'. | |
916 * If 'prop_types' is not NULL, then return only the text properties with | |
917 * matching property type in the 'prop_types' array. | |
918 * If 'prop_ids' is not NULL, then return only the text properties with | |
919 * an identifier in the 'props_ids' array. | |
920 * If 'add_lnum' is TRUE, then add the line number also to the text property | |
921 * dictionary. | |
922 */ | |
923 static void | |
924 get_props_in_line( | |
925 buf_T *buf, | |
926 linenr_T lnum, | |
927 int *prop_types, | |
928 int prop_types_len, | |
929 int *prop_ids, | |
930 int prop_ids_len, | |
931 list_T *retlist, | |
932 int add_lnum) | |
933 { | |
934 char_u *text = ml_get_buf(buf, lnum, FALSE); | |
935 size_t textlen = STRLEN(text) + 1; | |
936 int count; | |
937 int i; | |
938 textprop_T prop; | |
939 | |
940 count = (int)((buf->b_ml.ml_line_len - textlen) / sizeof(textprop_T)); | |
941 for (i = 0; i < count; ++i) | |
942 { | |
943 mch_memmove(&prop, text + textlen + i * sizeof(textprop_T), | |
944 sizeof(textprop_T)); | |
945 if ((prop_types == NULL | |
946 || prop_type_or_id_in_list(prop_types, prop_types_len, | |
947 prop.tp_type)) | |
948 && (prop_ids == NULL || | |
949 prop_type_or_id_in_list(prop_ids, prop_ids_len, | |
950 prop.tp_id))) | |
951 { | |
952 dict_T *d = dict_alloc(); | |
953 | |
954 if (d == NULL) | |
955 break; | |
956 prop_fill_dict(d, &prop, buf); | |
957 if (add_lnum) | |
958 dict_add_number(d, "lnum", lnum); | |
959 list_append_dict(retlist, d); | |
960 } | |
961 } | |
962 } | |
963 | |
964 /* | |
965 * Convert a List of property type names into an array of property type | |
966 * identifiers. Returns a pointer to the allocated array. Returns NULL on | |
967 * error. 'num_types' is set to the number of returned property types. | |
968 */ | |
969 static int * | |
970 get_prop_types_from_names(list_T *l, buf_T *buf, int *num_types) | |
971 { | |
972 int *prop_types; | |
973 listitem_T *li; | |
974 int i; | |
975 char_u *name; | |
976 proptype_T *type; | |
977 | |
978 *num_types = 0; | |
979 | |
980 prop_types = ALLOC_MULT(int, list_len(l)); | |
981 if (prop_types == NULL) | |
982 return NULL; | |
983 | |
984 i = 0; | |
985 FOR_ALL_LIST_ITEMS(l, li) | |
986 { | |
987 if (li->li_tv.v_type != VAR_STRING) | |
988 { | |
989 emsg(_(e_stringreq)); | |
990 goto errret; | |
991 } | |
992 name = li->li_tv.vval.v_string; | |
993 if (name == NULL) | |
994 goto errret; | |
995 | |
996 type = lookup_prop_type(name, buf); | |
997 if (type == NULL) | |
998 goto errret; | |
999 prop_types[i++] = type->pt_id; | |
1000 } | |
1001 | |
1002 *num_types = i; | |
1003 return prop_types; | |
1004 | |
1005 errret: | |
1006 VIM_CLEAR(prop_types); | |
1007 return NULL; | |
1008 } | |
1009 | |
1010 /* | |
1011 * Convert a List of property identifiers into an array of property | |
1012 * identifiers. Returns a pointer to the allocated array. Returns NULL on | |
1013 * error. 'num_ids' is set to the number of returned property identifiers. | |
1014 */ | |
1015 static int * | |
1016 get_prop_ids_from_list(list_T *l, int *num_ids) | |
1017 { | |
1018 int *prop_ids; | |
1019 listitem_T *li; | |
1020 int i; | |
1021 int id; | |
1022 int error; | |
1023 | |
1024 *num_ids = 0; | |
1025 | |
1026 prop_ids = ALLOC_MULT(int, list_len(l)); | |
1027 if (prop_ids == NULL) | |
1028 return NULL; | |
1029 | |
1030 i = 0; | |
1031 FOR_ALL_LIST_ITEMS(l, li) | |
1032 { | |
1033 error = FALSE; | |
1034 id = tv_get_number_chk(&li->li_tv, &error); | |
1035 if (error) | |
1036 goto errret; | |
1037 | |
1038 prop_ids[i++] = id; | |
1039 } | |
1040 | |
1041 *num_ids = i; | |
1042 return prop_ids; | |
1043 | |
1044 errret: | |
1045 VIM_CLEAR(prop_ids); | |
1046 return NULL; | |
1047 } | |
1048 | |
1049 /* | |
900 * prop_list({lnum} [, {bufnr}]) | 1050 * prop_list({lnum} [, {bufnr}]) |
901 */ | 1051 */ |
902 void | 1052 void |
903 f_prop_list(typval_T *argvars, typval_T *rettv) | 1053 f_prop_list(typval_T *argvars, typval_T *rettv) |
904 { | 1054 { |
905 linenr_T lnum; | 1055 linenr_T lnum; |
906 buf_T *buf = curbuf; | 1056 linenr_T start_lnum; |
1057 linenr_T end_lnum; | |
1058 buf_T *buf = curbuf; | |
1059 int add_lnum = FALSE; | |
1060 int *prop_types = NULL; | |
1061 int prop_types_len = 0; | |
1062 int *prop_ids = NULL; | |
1063 int prop_ids_len = 0; | |
1064 list_T *l; | |
1065 dictitem_T *di; | |
907 | 1066 |
908 if (in_vim9script() | 1067 if (in_vim9script() |
909 && (check_for_number_arg(argvars, 0) == FAIL | 1068 && (check_for_number_arg(argvars, 0) == FAIL |
910 || check_for_opt_dict_arg(argvars, 1) == FAIL)) | 1069 || check_for_opt_dict_arg(argvars, 1) == FAIL)) |
911 return; | 1070 return; |
912 | 1071 |
913 lnum = tv_get_number(&argvars[0]); | 1072 if (rettv_list_alloc(rettv) != OK) |
1073 return; | |
1074 | |
1075 // default: get text properties on current line | |
1076 start_lnum = tv_get_number(&argvars[0]); | |
1077 end_lnum = start_lnum; | |
914 if (argvars[1].v_type != VAR_UNKNOWN) | 1078 if (argvars[1].v_type != VAR_UNKNOWN) |
915 { | 1079 { |
1080 dict_T *d; | |
1081 | |
1082 if (argvars[1].v_type != VAR_DICT) | |
1083 { | |
1084 emsg(_(e_dictreq)); | |
1085 return; | |
1086 } | |
1087 d = argvars[1].vval.v_dict; | |
1088 | |
916 if (get_bufnr_from_arg(&argvars[1], &buf) == FAIL) | 1089 if (get_bufnr_from_arg(&argvars[1], &buf) == FAIL) |
917 return; | 1090 return; |
918 } | 1091 |
919 if (lnum < 1 || lnum > buf->b_ml.ml_line_count) | 1092 if (d != NULL && (di = dict_find(d, (char_u *)"end_lnum", -1)) != NULL) |
920 { | 1093 { |
1094 if (di->di_tv.v_type != VAR_NUMBER) | |
1095 { | |
1096 emsg(_(e_numberreq)); | |
1097 return; | |
1098 } | |
1099 end_lnum = tv_get_number(&di->di_tv); | |
1100 if (end_lnum < 0) | |
1101 // negative end_lnum is used as an offset from the last buffer | |
1102 // line | |
1103 end_lnum = buf->b_ml.ml_line_count + end_lnum + 1; | |
1104 else if (end_lnum > buf->b_ml.ml_line_count) | |
1105 end_lnum = buf->b_ml.ml_line_count; | |
1106 add_lnum = TRUE; | |
1107 } | |
1108 if (d != NULL && (di = dict_find(d, (char_u *)"types", -1)) != NULL) | |
1109 { | |
1110 if (di->di_tv.v_type != VAR_LIST) | |
1111 { | |
1112 emsg(_(e_listreq)); | |
1113 return; | |
1114 } | |
1115 | |
1116 l = di->di_tv.vval.v_list; | |
1117 if (l != NULL && list_len(l) > 0) | |
1118 { | |
1119 prop_types = get_prop_types_from_names(l, buf, &prop_types_len); | |
1120 if (prop_types == NULL) | |
1121 return; | |
1122 } | |
1123 } | |
1124 if (d != NULL && (di = dict_find(d, (char_u *)"ids", -1)) != NULL) | |
1125 { | |
1126 if (di->di_tv.v_type != VAR_LIST) | |
1127 { | |
1128 emsg(_(e_listreq)); | |
1129 goto errret; | |
1130 } | |
1131 | |
1132 l = di->di_tv.vval.v_list; | |
1133 if (l != NULL && list_len(l) > 0) | |
1134 { | |
1135 prop_ids = get_prop_ids_from_list(l, &prop_ids_len); | |
1136 if (prop_ids == NULL) | |
1137 goto errret; | |
1138 } | |
1139 } | |
1140 } | |
1141 if (start_lnum < 1 || start_lnum > buf->b_ml.ml_line_count | |
1142 || end_lnum < 1 || end_lnum < start_lnum) | |
921 emsg(_(e_invalid_range)); | 1143 emsg(_(e_invalid_range)); |
922 return; | 1144 else |
923 } | 1145 for (lnum = start_lnum; lnum <= end_lnum; lnum++) |
924 | 1146 get_props_in_line(buf, lnum, prop_types, prop_types_len, |
925 if (rettv_list_alloc(rettv) == OK) | 1147 prop_ids, prop_ids_len, |
926 { | 1148 rettv->vval.v_list, add_lnum); |
927 char_u *text = ml_get_buf(buf, lnum, FALSE); | 1149 |
928 size_t textlen = STRLEN(text) + 1; | 1150 errret: |
929 int count = (int)((buf->b_ml.ml_line_len - textlen) | 1151 VIM_CLEAR(prop_types); |
930 / sizeof(textprop_T)); | 1152 VIM_CLEAR(prop_ids); |
931 int i; | |
932 textprop_T prop; | |
933 | |
934 for (i = 0; i < count; ++i) | |
935 { | |
936 dict_T *d = dict_alloc(); | |
937 | |
938 if (d == NULL) | |
939 break; | |
940 mch_memmove(&prop, text + textlen + i * sizeof(textprop_T), | |
941 sizeof(textprop_T)); | |
942 prop_fill_dict(d, &prop, buf); | |
943 list_append_dict(rettv->vval.v_list, d); | |
944 } | |
945 } | |
946 } | 1153 } |
947 | 1154 |
948 /* | 1155 /* |
949 * prop_remove({props} [, {lnum} [, {lnum_end}]]) | 1156 * prop_remove({props} [, {lnum} [, {lnum_end}]]) |
950 */ | 1157 */ |