Function: bidi-find-overridden-directionality

bidi-find-overridden-directionality is a function defined in xdisp.c.

Signature

(bidi-find-overridden-directionality FROM TO &optional OBJECT)

Documentation

Return position between FROM and TO where directionality was overridden.

This function returns the first character position in the specified region of OBJECT where there is a character whose bidi-class property is L, but which was forced to display as R by a directional override, and likewise with characters whose bidi-class is R or AL that were forced to display as L.

If no such character is found, the function returns nil.

OBJECT is a Lisp string or buffer to search for overridden directionality, and defaults to the current buffer if nil or omitted. OBJECT can also be a window, in which case the function will search the buffer displayed in that window. Passing the window instead of a buffer is preferable when the buffer is displayed in some window, because this function will then be able to correctly account for window-specific overlays, which can affect the results.

Strong directional characters L, R, and AL can have their intrinsic directionality overridden by directional override control characters RLO (u+202e) and LRO (u+202d). See the function get-char-code-property for a way to inquire about the bidi-class property of a character.

Probably introduced at or before Emacs version 25.1.

Source Code

// Defined in /usr/src/emacs/src/xdisp.c
{
  struct buffer *buf = current_buffer;
  struct buffer *old = buf;
  struct window *w = NULL;
  bool frame_window_p = FRAME_WINDOW_P (SELECTED_FRAME ());
  struct bidi_it itb;
  ptrdiff_t from_pos, to_pos, from_bpos;
  void *itb_data;

  if (!NILP (object))
    {
      if (BUFFERP (object))
	buf = XBUFFER (object);
      else if (WINDOWP (object))
	{
	  w = decode_live_window (object);
	  buf = XBUFFER (w->contents);
	  frame_window_p = FRAME_WINDOW_P (XFRAME (w->frame));
	}
      else
	CHECK_STRING (object);
    }

  if (STRINGP (object))
    {
      /* Characters in unibyte strings are always treated by bidi.c as
	 strong LTR.  */
      if (!STRING_MULTIBYTE (object)
	  /* When we are loading loadup.el, the character property
	     tables needed for bidi iteration are not yet
	     available.  */
	  || redisplay__inhibit_bidi)
	return Qnil;

      validate_subarray (object, from, to, SCHARS (object), &from_pos, &to_pos);
      if (from_pos >= SCHARS (object))
	return Qnil;

      /* Set up the bidi iterator.  */
      itb_data = bidi_shelve_cache ();
      itb.paragraph_dir = NEUTRAL_DIR;
      itb.string.lstring = object;
      itb.string.s = NULL;
      itb.string.schars = SCHARS (object);
      itb.string.bufpos = 0;
      itb.string.from_disp_str = false;
      itb.string.unibyte = false;
      itb.w = w;
      bidi_init_it (0, 0, frame_window_p, &itb);
    }
  else
    {
      /* Nothing this fancy can happen in unibyte buffers, or in a
	 buffer that disabled reordering, or if FROM is at EOB.  */
      if (NILP (BVAR (buf, bidi_display_reordering))
	  || NILP (BVAR (buf, enable_multibyte_characters))
	  /* When we are loading loadup.el, the character property
	     tables needed for bidi iteration are not yet
	     available.  */
	  || redisplay__inhibit_bidi)
	return Qnil;

      set_buffer_temp (buf);
      validate_region (&from, &to);
      from_pos = XFIXNUM (from);
      to_pos = XFIXNUM (to);
      if (from_pos >= ZV)
	return Qnil;

      /* Set up the bidi iterator.  */
      itb_data = bidi_shelve_cache ();
      from_bpos = CHAR_TO_BYTE (from_pos);
      if (from_pos == BEGV)
	{
	  itb.charpos = BEGV;
	  itb.bytepos = BEGV_BYTE;
	}
      else if (FETCH_BYTE (from_bpos - 1) == '\n')
	{
	  itb.charpos = from_pos;
	  itb.bytepos = from_bpos;
	}
      else
	itb.charpos = find_newline_no_quit (from_pos, CHAR_TO_BYTE (from_pos),
					    -1, &itb.bytepos);
      itb.paragraph_dir = NEUTRAL_DIR;
      itb.string.s = NULL;
      itb.string.lstring = Qnil;
      itb.string.bufpos = 0;
      itb.string.from_disp_str = false;
      itb.string.unibyte = false;
      itb.w = w;
      bidi_init_it (itb.charpos, itb.bytepos, frame_window_p, &itb);
    }

  ptrdiff_t found;
  do {
    /* For the purposes of this function, the actual base direction of
       the paragraph doesn't matter, so just set it to L2R.  */
    bidi_paragraph_init (L2R, &itb, false);
    while ((found = bidi_find_first_overridden (&itb)) < from_pos)
      ;
  } while (found == ZV && itb.ch == '\n' && itb.charpos < to_pos);

  bidi_unshelve_cache (itb_data, false);
  set_buffer_temp (old);

  return (from_pos <= found && found < to_pos) ? make_fixnum (found) : Qnil;
}