Mercurial > emacs
comparison src/keymap.c @ 67904:d2dff317d618
(describe_map): Put sparse map elements into an array,
sort them, then output a sequence of identical bindings on one line.
(struct describe_map_elt): New data type.
(describe_map_compare): New function.
author | Richard M. Stallman <rms@gnu.org> |
---|---|
date | Fri, 30 Dec 2005 04:52:16 +0000 |
parents | e7b90ba8a38a |
children | 2e977adcc0e5 c69d44922688 |
comparison
equal
deleted
inserted
replaced
67903:a57273fb71d3 | 67904:d2dff317d618 |
---|---|
3172 insert_string ("Prefix Command\n"); | 3172 insert_string ("Prefix Command\n"); |
3173 else | 3173 else |
3174 insert_string ("??\n"); | 3174 insert_string ("??\n"); |
3175 } | 3175 } |
3176 | 3176 |
3177 /* describe_map puts all the usable elements of a sparse keymap | |
3178 into an array of `struct describe_map_elt', | |
3179 then sorts them by the events. */ | |
3180 | |
3181 struct describe_map_elt { Lisp_Object event; Lisp_Object definition; int shadowed; }; | |
3182 | |
3183 /* qsort comparison function for sorting `struct describe_map_elt' by | |
3184 the event field. */ | |
3185 | |
3186 static int | |
3187 describe_map_compare (aa, bb) | |
3188 const void *aa, *bb; | |
3189 { | |
3190 const struct describe_map_elt *a = aa, *b = bb; | |
3191 if (INTEGERP (a->event) && INTEGERP (b->event)) | |
3192 return ((XINT (a->event) > XINT (b->event)) | |
3193 - (XINT (a->event) < XINT (b->event))); | |
3194 if (!INTEGERP (a->event) && INTEGERP (b->event)) | |
3195 return 1; | |
3196 if (INTEGERP (a->event) && !INTEGERP (b->event)) | |
3197 return -1; | |
3198 if (SYMBOLP (a->event) && SYMBOLP (b->event)) | |
3199 return (Fstring_lessp (a->event, b->event) ? -1 | |
3200 : Fstring_lessp (b->event, a->event) ? 1 | |
3201 : 0); | |
3202 return 0; | |
3203 } | |
3204 | |
3177 /* Describe the contents of map MAP, assuming that this map itself is | 3205 /* Describe the contents of map MAP, assuming that this map itself is |
3178 reached by the sequence of prefix keys PREFIX (a string or vector). | 3206 reached by the sequence of prefix keys PREFIX (a string or vector). |
3179 PARTIAL, SHADOW, NOMENU are as in `describe_map_tree' above. */ | 3207 PARTIAL, SHADOW, NOMENU are as in `describe_map_tree' above. */ |
3180 | 3208 |
3181 static void | 3209 static void |
3195 Lisp_Object suppress; | 3223 Lisp_Object suppress; |
3196 Lisp_Object kludge; | 3224 Lisp_Object kludge; |
3197 int first = 1; | 3225 int first = 1; |
3198 struct gcpro gcpro1, gcpro2, gcpro3; | 3226 struct gcpro gcpro1, gcpro2, gcpro3; |
3199 | 3227 |
3228 /* These accumulate the values from sparse keymap bindings, | |
3229 so we can sort them and handle them in order. */ | |
3230 int length_needed = 0; | |
3231 struct describe_map_elt *vect; | |
3232 int slots_used = 0; | |
3233 int i; | |
3234 | |
3200 suppress = Qnil; | 3235 suppress = Qnil; |
3201 | 3236 |
3202 if (partial) | 3237 if (partial) |
3203 suppress = intern ("suppress-keymap"); | 3238 suppress = intern ("suppress-keymap"); |
3204 | 3239 |
3205 /* This vector gets used to present single keys to Flookup_key. Since | 3240 /* This vector gets used to present single keys to Flookup_key. Since |
3206 that is done once per keymap element, we don't want to cons up a | 3241 that is done once per keymap element, we don't want to cons up a |
3207 fresh vector every time. */ | 3242 fresh vector every time. */ |
3208 kludge = Fmake_vector (make_number (1), Qnil); | 3243 kludge = Fmake_vector (make_number (1), Qnil); |
3209 definition = Qnil; | 3244 definition = Qnil; |
3245 | |
3246 for (tail = map; CONSP (tail); tail = XCDR (tail)) | |
3247 length_needed++; | |
3248 | |
3249 vect = ((struct describe_map_elt *) | |
3250 alloca (sizeof (struct describe_map_elt) * length_needed)); | |
3210 | 3251 |
3211 GCPRO3 (prefix, definition, kludge); | 3252 GCPRO3 (prefix, definition, kludge); |
3212 | 3253 |
3213 for (tail = map; CONSP (tail); tail = XCDR (tail)) | 3254 for (tail = map; CONSP (tail); tail = XCDR (tail)) |
3214 { | 3255 { |
3220 prefix, Qnil, elt_describer, partial, shadow, map, | 3261 prefix, Qnil, elt_describer, partial, shadow, map, |
3221 (int *)0, 0, 1, mention_shadow); | 3262 (int *)0, 0, 1, mention_shadow); |
3222 else if (CONSP (XCAR (tail))) | 3263 else if (CONSP (XCAR (tail))) |
3223 { | 3264 { |
3224 int this_shadowed = 0; | 3265 int this_shadowed = 0; |
3266 | |
3225 event = XCAR (XCAR (tail)); | 3267 event = XCAR (XCAR (tail)); |
3226 | 3268 |
3227 /* Ignore bindings whose "prefix" are not really valid events. | 3269 /* Ignore bindings whose "prefix" are not really valid events. |
3228 (We get these in the frames and buffers menu.) */ | 3270 (We get these in the frames and buffers menu.) */ |
3229 if (!(SYMBOLP (event) || INTEGERP (event))) | 3271 if (!(SYMBOLP (event) || INTEGERP (event))) |
3260 } | 3302 } |
3261 | 3303 |
3262 tem = Flookup_key (map, kludge, Qt); | 3304 tem = Flookup_key (map, kludge, Qt); |
3263 if (!EQ (tem, definition)) continue; | 3305 if (!EQ (tem, definition)) continue; |
3264 | 3306 |
3265 if (first) | 3307 vect[slots_used].event = event; |
3266 { | 3308 vect[slots_used].definition = definition; |
3267 previous_description_column = 0; | 3309 vect[slots_used].shadowed = this_shadowed; |
3268 insert ("\n", 1); | 3310 slots_used++; |
3269 first = 0; | |
3270 } | |
3271 | |
3272 /* THIS gets the string to describe the character EVENT. */ | |
3273 insert1 (Fkey_description (kludge, prefix)); | |
3274 | |
3275 /* Print a description of the definition of this character. | |
3276 elt_describer will take care of spacing out far enough | |
3277 for alignment purposes. */ | |
3278 (*elt_describer) (definition, Qnil); | |
3279 | |
3280 if (this_shadowed) | |
3281 { | |
3282 SET_PT (PT - 1); | |
3283 insert_string (" (binding currently shadowed)"); | |
3284 SET_PT (PT + 1); | |
3285 } | |
3286 } | 3311 } |
3287 else if (EQ (XCAR (tail), Qkeymap)) | 3312 else if (EQ (XCAR (tail), Qkeymap)) |
3288 { | 3313 { |
3289 /* The same keymap might be in the structure twice, if we're | 3314 /* The same keymap might be in the structure twice, if we're |
3290 using an inherited keymap. So skip anything we've already | 3315 using an inherited keymap. So skip anything we've already |
3291 encountered. */ | 3316 encountered. */ |
3292 tem = Fassq (tail, *seen); | 3317 tem = Fassq (tail, *seen); |
3293 if (CONSP (tem) && !NILP (Fequal (XCAR (tem), prefix))) | 3318 if (CONSP (tem) && !NILP (Fequal (XCAR (tem), prefix))) |
3294 break; | 3319 break; |
3295 *seen = Fcons (Fcons (tail, prefix), *seen); | 3320 *seen = Fcons (Fcons (tail, prefix), *seen); |
3321 } | |
3322 } | |
3323 | |
3324 /* If we found some sparse map events, sort them. */ | |
3325 | |
3326 qsort (vect, slots_used, sizeof (struct describe_map_elt), | |
3327 describe_map_compare); | |
3328 | |
3329 /* Now output them in sorted order. */ | |
3330 | |
3331 for (i = 0; i < slots_used; i++) | |
3332 { | |
3333 Lisp_Object start, end; | |
3334 | |
3335 if (first) | |
3336 { | |
3337 previous_description_column = 0; | |
3338 insert ("\n", 1); | |
3339 first = 0; | |
3340 } | |
3341 | |
3342 ASET (kludge, 0, vect[i].event); | |
3343 start = vect[i].event; | |
3344 end = start; | |
3345 | |
3346 definition = vect[i].definition; | |
3347 | |
3348 /* Find consecutive chars that are identically defined. */ | |
3349 if (INTEGERP (vect[i].event)) | |
3350 { | |
3351 while (i + 1 < slots_used | |
3352 && XINT (vect[i + 1].event) == XINT (vect[i].event) + 1 | |
3353 && !NILP (Fequal (vect[i + 1].definition, definition)) | |
3354 && vect[i].shadowed == vect[i + 1].shadowed) | |
3355 i++; | |
3356 end = vect[i].event; | |
3357 } | |
3358 | |
3359 /* Now START .. END is the range to describe next. */ | |
3360 | |
3361 /* Insert the string to describe the event START. */ | |
3362 insert1 (Fkey_description (kludge, prefix)); | |
3363 | |
3364 if (!EQ (start, end)) | |
3365 { | |
3366 insert (" .. ", 4); | |
3367 | |
3368 ASET (kludge, 0, end); | |
3369 /* Insert the string to describe the character END. */ | |
3370 insert1 (Fkey_description (kludge, prefix)); | |
3371 } | |
3372 | |
3373 /* Print a description of the definition of this character. | |
3374 elt_describer will take care of spacing out far enough | |
3375 for alignment purposes. */ | |
3376 (*elt_describer) (vect[i].definition, Qnil); | |
3377 | |
3378 if (vect[i].shadowed) | |
3379 { | |
3380 SET_PT (PT - 1); | |
3381 insert_string (" (binding currently shadowed)"); | |
3382 SET_PT (PT + 1); | |
3296 } | 3383 } |
3297 } | 3384 } |
3298 | 3385 |
3299 UNGCPRO; | 3386 UNGCPRO; |
3300 } | 3387 } |