diff options
| author | Lars Ingebrigtsen | 2021-11-24 11:55:53 +0100 |
|---|---|---|
| committer | Lars Ingebrigtsen | 2021-11-24 11:55:58 +0100 |
| commit | a13b437c81f1f2e54555e7281480ea7e8eee8753 (patch) | |
| tree | 602c0751912e81fef3113bd47720bdad4d649e9e /src | |
| parent | 8efee422e1915a000f7220e680e3165407171388 (diff) | |
| download | emacs-a13b437c81f1f2e54555e7281480ea7e8eee8753.tar.gz emacs-a13b437c81f1f2e54555e7281480ea7e8eee8753.zip | |
Add support for the min-width display property
* doc/lispref/display.texi (Display Property): Document
get-display-property.
(Other Display Specs): Document min-width property.
* src/dispextern.h (struct it): Add fields for min-width handling.
* src/xdisp.c (find_display_property, get_display_property): New
helper functions.
(display_min_width): Insert stretch glyphs based on the min width.
(Fget_display_property): New defun.
(handle_display_prop): Handle min-width ends.
(handle_single_display_spec): Handle min-width starts.
Diffstat (limited to 'src')
| -rw-r--r-- | src/dispextern.h | 6 | ||||
| -rw-r--r-- | src/xdisp.c | 172 |
2 files changed, 175 insertions, 3 deletions
diff --git a/src/dispextern.h b/src/dispextern.h index a698f6546b1..088297157ac 100644 --- a/src/dispextern.h +++ b/src/dispextern.h | |||
| @@ -2746,6 +2746,12 @@ struct it | |||
| 2746 | /* For iterating over bidirectional text. */ | 2746 | /* For iterating over bidirectional text. */ |
| 2747 | struct bidi_it bidi_it; | 2747 | struct bidi_it bidi_it; |
| 2748 | bidi_dir_t paragraph_embedding; | 2748 | bidi_dir_t paragraph_embedding; |
| 2749 | |||
| 2750 | /* For handling the :min-width property. The object is the text | ||
| 2751 | property we're testing the `eq' of (nil if none), and the integer | ||
| 2752 | is the x position of the start of the run of glyphs. */ | ||
| 2753 | Lisp_Object min_width_property; | ||
| 2754 | int min_width_start; | ||
| 2749 | }; | 2755 | }; |
| 2750 | 2756 | ||
| 2751 | 2757 | ||
diff --git a/src/xdisp.c b/src/xdisp.c index 11ea8360343..4d3b4878058 100644 --- a/src/xdisp.c +++ b/src/xdisp.c | |||
| @@ -822,6 +822,9 @@ bool help_echo_showing_p; | |||
| 822 | /* Functions to mark elements as needing redisplay. */ | 822 | /* Functions to mark elements as needing redisplay. */ |
| 823 | enum { REDISPLAY_SOME = 2}; /* Arbitrary choice. */ | 823 | enum { REDISPLAY_SOME = 2}; /* Arbitrary choice. */ |
| 824 | 824 | ||
| 825 | static bool calc_pixel_width_or_height (double *, struct it *, Lisp_Object, | ||
| 826 | struct font *, bool, int *); | ||
| 827 | |||
| 825 | void | 828 | void |
| 826 | redisplay_other_windows (void) | 829 | redisplay_other_windows (void) |
| 827 | { | 830 | { |
| @@ -5141,6 +5144,149 @@ setup_for_ellipsis (struct it *it, int len) | |||
| 5141 | it->ellipsis_p = true; | 5144 | it->ellipsis_p = true; |
| 5142 | } | 5145 | } |
| 5143 | 5146 | ||
| 5147 | |||
| 5148 | static Lisp_Object | ||
| 5149 | find_display_property (Lisp_Object disp, Lisp_Object prop) | ||
| 5150 | { | ||
| 5151 | if (NILP (disp)) | ||
| 5152 | return Qnil; | ||
| 5153 | /* We have a vector of display specs. */ | ||
| 5154 | if (VECTORP (disp)) | ||
| 5155 | { | ||
| 5156 | for (ptrdiff_t i = 0; i < ASIZE (disp); i++) | ||
| 5157 | { | ||
| 5158 | Lisp_Object elem = AREF (disp, i); | ||
| 5159 | if (CONSP (elem) | ||
| 5160 | && CONSP (XCDR (elem)) | ||
| 5161 | && EQ (XCAR (elem), prop)) | ||
| 5162 | return XCAR (XCDR (elem)); | ||
| 5163 | } | ||
| 5164 | return Qnil; | ||
| 5165 | } | ||
| 5166 | /* We have a list of display specs. */ | ||
| 5167 | else if (CONSP (disp) | ||
| 5168 | && CONSP (XCAR (disp))) | ||
| 5169 | { | ||
| 5170 | while (!NILP (disp)) | ||
| 5171 | { | ||
| 5172 | Lisp_Object elem = XCAR (disp); | ||
| 5173 | if (CONSP (elem) | ||
| 5174 | && CONSP (XCDR (elem)) | ||
| 5175 | && EQ (XCAR (elem), prop)) | ||
| 5176 | return XCAR (XCDR (elem)); | ||
| 5177 | |||
| 5178 | /* Check that we have a proper list before going to the next | ||
| 5179 | element. */ | ||
| 5180 | if (CONSP (XCDR (disp))) | ||
| 5181 | disp = XCDR (disp); | ||
| 5182 | else | ||
| 5183 | disp = Qnil; | ||
| 5184 | } | ||
| 5185 | return Qnil; | ||
| 5186 | } | ||
| 5187 | /* A simple display spec. */ | ||
| 5188 | else if (CONSP (disp) | ||
| 5189 | && CONSP (XCDR (disp)) | ||
| 5190 | && EQ (XCAR (disp), prop)) | ||
| 5191 | return XCAR (XCDR (disp)); | ||
| 5192 | else | ||
| 5193 | return Qnil; | ||
| 5194 | } | ||
| 5195 | |||
| 5196 | static Lisp_Object get_display_property (ptrdiff_t bufpos, Lisp_Object prop, | ||
| 5197 | Lisp_Object object) | ||
| 5198 | { | ||
| 5199 | return find_display_property (Fget_text_property (make_fixnum (bufpos), | ||
| 5200 | |||
| 5201 | Qdisplay, object), | ||
| 5202 | prop); | ||
| 5203 | } | ||
| 5204 | |||
| 5205 | static void | ||
| 5206 | display_min_width (struct it *it, ptrdiff_t bufpos, | ||
| 5207 | Lisp_Object object, Lisp_Object width_spec) | ||
| 5208 | { | ||
| 5209 | /* We're being called at the end of the `min-width' sequence, | ||
| 5210 | probably. */ | ||
| 5211 | if (!NILP (it->min_width_property) | ||
| 5212 | && !EQ (width_spec, it->min_width_property)) | ||
| 5213 | { | ||
| 5214 | if (!it->glyph_row) | ||
| 5215 | return; | ||
| 5216 | |||
| 5217 | /* Check that we're really right after the sequence of | ||
| 5218 | characters covered by this `min-width'. */ | ||
| 5219 | if (bufpos > BEGV | ||
| 5220 | && EQ (it->min_width_property, | ||
| 5221 | get_display_property (bufpos - 1, Qmin_width, object))) | ||
| 5222 | { | ||
| 5223 | Lisp_Object w = Qnil; | ||
| 5224 | double width; | ||
| 5225 | #ifdef HAVE_WINDOW_SYSTEM | ||
| 5226 | if (FRAME_WINDOW_P (it->f)) | ||
| 5227 | { | ||
| 5228 | struct font *font = NULL; | ||
| 5229 | struct face *face = FACE_FROM_ID (it->f, it->face_id); | ||
| 5230 | font = face->font ? face->font : FRAME_FONT (it->f); | ||
| 5231 | calc_pixel_width_or_height (&width, it, | ||
| 5232 | XCAR (it->min_width_property), | ||
| 5233 | font, true, NULL); | ||
| 5234 | width -= it->current_x - it->min_width_start; | ||
| 5235 | w = list1 (make_int (width)); | ||
| 5236 | } | ||
| 5237 | else | ||
| 5238 | #endif | ||
| 5239 | { | ||
| 5240 | calc_pixel_width_or_height (&width, it, | ||
| 5241 | XCAR (it->min_width_property), | ||
| 5242 | NULL, true, NULL); | ||
| 5243 | width -= (it->current_x - it->min_width_start) / | ||
| 5244 | FRAME_COLUMN_WIDTH (it->f); | ||
| 5245 | w = make_int (width); | ||
| 5246 | } | ||
| 5247 | |||
| 5248 | /* Insert the stretch glyph. */ | ||
| 5249 | it->object = list3 (Qspace, QCwidth, w); | ||
| 5250 | produce_stretch_glyph (it); | ||
| 5251 | it->min_width_property = Qnil; | ||
| 5252 | } | ||
| 5253 | } | ||
| 5254 | |||
| 5255 | /* We're at the start of a `min-width' sequence -- record the | ||
| 5256 | position and the property, so that we can later see if we're at | ||
| 5257 | the end. */ | ||
| 5258 | if (CONSP (width_spec)) | ||
| 5259 | { | ||
| 5260 | if (bufpos == BEGV | ||
| 5261 | || (bufpos > BEGV | ||
| 5262 | && !EQ (width_spec, | ||
| 5263 | get_display_property (bufpos - 1, Qmin_width, object)))) | ||
| 5264 | { | ||
| 5265 | it->min_width_property = width_spec; | ||
| 5266 | it->min_width_start = it->current_x; | ||
| 5267 | } | ||
| 5268 | } | ||
| 5269 | } | ||
| 5270 | |||
| 5271 | DEFUN ("get-display-property", Fget_display_property, | ||
| 5272 | Sget_display_property, 2, 4, 0, | ||
| 5273 | doc: /* Get the `display' property PROP at POSITION. | ||
| 5274 | If OBJECT, this should be a buffer or string where the property is | ||
| 5275 | fetched from. This defaults to the current buffer. | ||
| 5276 | |||
| 5277 | If PROPERTIES, use those properties instead of the properties at | ||
| 5278 | POSITION. */) | ||
| 5279 | (Lisp_Object position, Lisp_Object prop, Lisp_Object object, | ||
| 5280 | Lisp_Object properties) | ||
| 5281 | { | ||
| 5282 | if (NILP (properties)) | ||
| 5283 | properties = Fget_text_property (position, Qdisplay, object); | ||
| 5284 | else | ||
| 5285 | CHECK_LIST (properties); | ||
| 5286 | |||
| 5287 | return find_display_property (properties, prop); | ||
| 5288 | } | ||
| 5289 | |||
| 5144 | 5290 | ||
| 5145 | 5291 | ||
| 5146 | /*********************************************************************** | 5292 | /*********************************************************************** |
| @@ -5187,16 +5333,22 @@ handle_display_prop (struct it *it) | |||
| 5187 | if (!it->string_from_display_prop_p) | 5333 | if (!it->string_from_display_prop_p) |
| 5188 | it->area = TEXT_AREA; | 5334 | it->area = TEXT_AREA; |
| 5189 | 5335 | ||
| 5336 | if (!STRINGP (it->string)) | ||
| 5337 | object = it->w->contents; | ||
| 5338 | |||
| 5190 | propval = get_char_property_and_overlay (make_fixnum (position->charpos), | 5339 | propval = get_char_property_and_overlay (make_fixnum (position->charpos), |
| 5191 | Qdisplay, object, &overlay); | 5340 | Qdisplay, object, &overlay); |
| 5341 | |||
| 5342 | /* Handle min-width ends. */ | ||
| 5343 | if (! NILP (it->min_width_property) | ||
| 5344 | && NILP (find_display_property (propval, Qmin_width))) | ||
| 5345 | display_min_width (it, bufpos, object, Qnil); | ||
| 5346 | |||
| 5192 | if (NILP (propval)) | 5347 | if (NILP (propval)) |
| 5193 | return HANDLED_NORMALLY; | 5348 | return HANDLED_NORMALLY; |
| 5194 | /* Now OVERLAY is the overlay that gave us this property, or nil | 5349 | /* Now OVERLAY is the overlay that gave us this property, or nil |
| 5195 | if it was a text property. */ | 5350 | if it was a text property. */ |
| 5196 | 5351 | ||
| 5197 | if (!STRINGP (it->string)) | ||
| 5198 | object = it->w->contents; | ||
| 5199 | |||
| 5200 | display_replaced = handle_display_spec (it, propval, object, overlay, | 5352 | display_replaced = handle_display_spec (it, propval, object, overlay, |
| 5201 | position, bufpos, | 5353 | position, bufpos, |
| 5202 | FRAME_WINDOW_P (it->f)); | 5354 | FRAME_WINDOW_P (it->f)); |
| @@ -5250,6 +5402,7 @@ handle_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, | |||
| 5250 | && !(CONSP (XCAR (spec)) && EQ (XCAR (XCAR (spec)), Qmargin)) | 5402 | && !(CONSP (XCAR (spec)) && EQ (XCAR (XCAR (spec)), Qmargin)) |
| 5251 | && !EQ (XCAR (spec), Qleft_fringe) | 5403 | && !EQ (XCAR (spec), Qleft_fringe) |
| 5252 | && !EQ (XCAR (spec), Qright_fringe) | 5404 | && !EQ (XCAR (spec), Qright_fringe) |
| 5405 | && !EQ (XCAR (spec), Qmin_width) | ||
| 5253 | && !NILP (XCAR (spec))) | 5406 | && !NILP (XCAR (spec))) |
| 5254 | { | 5407 | { |
| 5255 | for (; CONSP (spec); spec = XCDR (spec)) | 5408 | for (; CONSP (spec); spec = XCDR (spec)) |
| @@ -5483,6 +5636,17 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, | |||
| 5483 | return 0; | 5636 | return 0; |
| 5484 | } | 5637 | } |
| 5485 | 5638 | ||
| 5639 | /* Handle `(min-width (WIDTH))'. */ | ||
| 5640 | if (CONSP (spec) | ||
| 5641 | && EQ (XCAR (spec), Qmin_width) | ||
| 5642 | && CONSP (XCDR (spec)) | ||
| 5643 | && CONSP (XCAR (XCDR (spec)))) | ||
| 5644 | { | ||
| 5645 | if (it) | ||
| 5646 | display_min_width (it, bufpos, object, XCAR (XCDR (spec))); | ||
| 5647 | return 0; | ||
| 5648 | } | ||
| 5649 | |||
| 5486 | /* Handle `(slice X Y WIDTH HEIGHT)'. */ | 5650 | /* Handle `(slice X Y WIDTH HEIGHT)'. */ |
| 5487 | if (CONSP (spec) | 5651 | if (CONSP (spec) |
| 5488 | && EQ (XCAR (spec), Qslice)) | 5652 | && EQ (XCAR (spec), Qslice)) |
| @@ -7186,6 +7350,7 @@ reseat_1 (struct it *it, struct text_pos pos, bool set_stop_p) | |||
| 7186 | } | 7350 | } |
| 7187 | /* This make the information stored in it->cmp_it invalidate. */ | 7351 | /* This make the information stored in it->cmp_it invalidate. */ |
| 7188 | it->cmp_it.id = -1; | 7352 | it->cmp_it.id = -1; |
| 7353 | it->min_width_property = Qnil; | ||
| 7189 | } | 7354 | } |
| 7190 | 7355 | ||
| 7191 | 7356 | ||
| @@ -35121,6 +35286,7 @@ be let-bound around code that needs to disable messages temporarily. */); | |||
| 35121 | defsubr (&Smove_point_visually); | 35286 | defsubr (&Smove_point_visually); |
| 35122 | defsubr (&Sbidi_find_overridden_directionality); | 35287 | defsubr (&Sbidi_find_overridden_directionality); |
| 35123 | defsubr (&Sdisplay__line_is_continued_p); | 35288 | defsubr (&Sdisplay__line_is_continued_p); |
| 35289 | defsubr (&Sget_display_property); | ||
| 35124 | 35290 | ||
| 35125 | DEFSYM (Qmenu_bar_update_hook, "menu-bar-update-hook"); | 35291 | DEFSYM (Qmenu_bar_update_hook, "menu-bar-update-hook"); |
| 35126 | DEFSYM (Qoverriding_terminal_local_map, "overriding-terminal-local-map"); | 35292 | DEFSYM (Qoverriding_terminal_local_map, "overriding-terminal-local-map"); |