remacs icon indicating copy to clipboard operation
remacs copied to clipboard

Port char-width

Open brotzeit opened this issue 7 years ago • 20 comments

DEFUN ("char-width", Fchar_width, Schar_width, 1, 1, 0,
       doc: /* Return width of CHAR when displayed in the current buffer.
The width is measured by how many columns it occupies on the screen.
Tab is taken to occupy `tab-width' columns.
usage: (char-width CHAR)  */)
  (Lisp_Object ch)
{
  int c;
  ptrdiff_t width;

  CHECK_CHARACTER (ch);
  c = XINT (ch);
  width = char_width (c, buffer_display_table ());
  return make_number (width);
}

brotzeit avatar Dec 19 '18 09:12 brotzeit

I'd like to port this function. Presumably, I'll also need to port the function char_width, but I'm not sure what to do with buffer_display_table, i.e. I'm not sure where it's defined, or whether I can access it from Rust. I'd appreciate a little help.

Bolt64 avatar Dec 21 '18 04:12 Bolt64

You can start by calling them both from C.

https://github.com/emacs-mirror/emacs/blob/78ec68e18f07a90a9ad400683b973ff51baa80e1/src/indent.c#L60

All C functions can be imported from remacs_sys.

shaleh avatar Dec 21 '18 04:12 shaleh

Would anyone mind if I have a go at this?

NQNStudios avatar Apr 17 '19 23:04 NQNStudios

A simple port to Rust would call the C functions. Which is why this is labelled as a good first issue. A more interesting port would look at the C functions called and bring them along too.

shaleh avatar Apr 18 '19 00:04 shaleh

I'm looking at the C function buffer_display_table, which references macros BVAR, XCHAR_TABLE, and DISP_TABLE_P. I found the definition for BVAR and DISP_TABLE_P, but not XCHAR_TABLE or at least one of the macros used by DISP_TABLE_P. I'm using rg to try and find original definitions in the C code. Are those macros I'm missing defined in external C libraries?

Trying to delve into the C for a better understanding, but in the meantime I'll go for the simple port option and open a WIP PR.

NQNStudios avatar Apr 19 '19 01:04 NQNStudios

INLINE struct Lisp_Char_Table *
XCHAR_TABLE (Lisp_Object a)
{
  eassert (CHAR_TABLE_P (a));
  return XUNTAG (a, Lisp_Vectorlike);
}

Defined around line 1818 of lisp.h.

In general XFOO means "hard cast to FOO, do no checks". This is an exception.

shaleh avatar Apr 19 '19 01:04 shaleh

BTW, check out https://github.com/Wilfred/deadgrep I have it bound to C-c g.

shaleh avatar Apr 19 '19 01:04 shaleh

So my rg didn't find it because it's not a #define macro. Is it a macro at all? Is INLINE a macro that contains a nested #define? What's a better regex to search for definitions of X___() conversions?

NQNStudios avatar Apr 19 '19 01:04 NQNStudios

I guess by using into() I shouldn't necessarily need to understand what types the C functions are using?

NQNStudios avatar Apr 19 '19 01:04 NQNStudios

I see from the most recent commit that make_number is no longer a thing? Should I replace the usage of make_number in the C char_width() function with a match val.into() expression like is used here?

If that's the case, is it an idiom that we could DRY somehow, either with a function or a macro?

NQNStudios avatar Apr 19 '19 05:04 NQNStudios

I think we shouldn't use into too much. You can return width as EmacsInt.

brotzeit avatar Apr 21 '19 07:04 brotzeit

Probably it's ok if you use into when the return type is EmacsInt. But I don't like it when you can't see the resulting type.

brotzeit avatar Apr 21 '19 07:04 brotzeit

INLINE in C works like the inline directive in Rust. It causes the compiler to replace every instance where the function would be called with the code of the function instead. This reduces oveerhead of building call stacks, jumping in and out of functions, etc. Mentally it behaves like a macro but you have to reason about it as if it is a function.

shaleh avatar Apr 23 '19 00:04 shaleh

As for finding the XFOO items look for the define, then look for a line starting with XFOO. That will catch inlines. Or simply look at headers which is all you need to learn about the type.

shaleh avatar Apr 23 '19 00:04 shaleh

We consider the into and from usage reasonably DRY. We have been adding force_foo methods lately to mimic the XFOO behavior of not performing checking where it makes sense. Essentially the X routines in C are equivalent to thing.into().unwrap() most of the time.

shaleh avatar Apr 23 '19 00:04 shaleh

These are all really good questions @NQNStudios. Thanks for taking the time.

shaleh avatar Apr 23 '19 00:04 shaleh

Is this fine?

use crate::{
   // ...
    remacs_sys::{buffer_display_table, char_width, CHECK_CHARACTER},
};

/// Return width of CHAR when displayed in the current buffer.
/// The width is measured by how many columns it occupies on the screen.
/// Tab is taken to occupy `tab-width' columns.
#[lisp_fn(c_name = "char_width", name = "char-width")]
pub fn char_width_lisp(ch: LispObject) -> EmacsInt {
    CHECK_CHARACTER(ch);
    let c: usize = ch.into().unwrap();
    let width = char_width(c, buffer_display_table());
    width.into().unwrap()
}

EDIT: this is NOT fine.

A6GibKm avatar Oct 02 '19 18:10 A6GibKm

@A6GibKm why is this not fine? would you like to elaborate? would be nice to finish this task, seems like you almost got it ;)

denis631 avatar Dec 27 '19 16:12 denis631

It compiles, but the results I got from the function are not accurate.

A6GibKm avatar Dec 27 '19 20:12 A6GibKm

@A6GibKm please post a PR, then we can comment on the code as you make progress.

shaleh avatar Jan 06 '20 17:01 shaleh