native icon indicating copy to clipboard operation
native copied to clipboard

Add option for dart-idiomatic renaming

Open safasofuoglu opened this issue 4 years ago • 7 comments
trafficstars

UpperCamelCase for structs, lowerCamelCase for functions and members. Current regex-based rename mechanism is unable to achieve this with snake_case symbols.

Better if it can coexist with the existing regex-based rename (to be run before or after).

safasofuoglu avatar Jul 08 '21 20:07 safasofuoglu

Hi @safasofuoglu, I haven't been able to find any standard or widely used way for doing this via regexp. The current regexp replace design is very similar to VSCode's. Let us know if you have any design suggestions for this. We'd ideally want to be able to capitalise words or letters via the regexp replace syntax. I'll try to find something as well.

mannprerak2 avatar Jul 09 '21 03:07 mannprerak2

Hi @mannprerak2. Doing this via regex is not possible, since it requires character case transformations which is beyond the capabilities of ECMA regex.

Implementation can be inspired from: https://github.com/Ephenodrom/Dart-Basic-Utils/blob/898970fb31cfbed17366dc9593d474730634616f/lib/src/StringUtils.dart#L32 (MIT)

Design-wise, my suggestion is a root-level configuration:

dart-style-rename: true | false

Renames all identifiers based on the guidelines specified in 
https://dart.dev/guides/language/effective-dart/style.
Runs after regex-based renames.
default: false

If granularity is desired, key can be replicated in specific configs, root-level one serving as the default. Example:

dart-style-rename: true
functions:
  rename:
    'clang_(.*)': '$1'
  dart-style-rename: false

For me, this granularity is not important. I just want dart code to look like other dart code.

safasofuoglu avatar Jul 09 '21 13:07 safasofuoglu

In general this seems a fine feature to me.

I just want dart code to look like other dart code.

However, this can never be true. Because you have to think about resource management: freeing malloced memory, releasing file handles, closing SQLite statements, etc. (Unless you're writing very simple functions that take in all their arguments by value and return a single result by value.)

I think the right mental model with FFI code is that you're writing C code in Dart syntax. And then wrap that code in an object oriented API. It might be actually kind of helpful if those C function in Dart syntax actually have C naming conventions. But of course that is a matter of preference.

dcharkes avatar Jul 09 '21 13:07 dcharkes

That's a good point. What I'm currently working on abstracts away memory/resource management, so I haven't thought that way.

safasofuoglu avatar Jul 09 '21 14:07 safasofuoglu

IMO it would be better to just make ffigen more customizable. Instead of relying on yaml, provide better support for using ffigen as library:

Possible API:

final config = YamlConfig.fromFile(File('ffigen.yaml'));
final customizable = CustomizableConfig(config)
customizable.enumClassDecl.customizeRename((x) => x.camelCase);
FfiGen().run(customizable)

szotp avatar May 03 '25 06:05 szotp

IMO it would be better to just make ffigen more customizable. Instead of relying on yaml, provide better support for using ffigen as library:

Possible API:

final config = YamlConfig.fromFile(File('ffigen.yaml')); final customizable = CustomizableConfig(config) customizable.enumClassDecl.customizeRename((x) => x.camelCase); FfiGen().run(customizable)

Similar effort is happening for jnigen: https://github.com/dart-lang/native/issues/1171

HosseinYousefi avatar May 05 '25 08:05 HosseinYousefi

Cool. Another benefit of code based approach is being able to use pub.dev. For example a very common pattern in ffi is pseudo OOP with methods having an opaque pointer as first argument.

@ffi.Native<ffi.Void Function(ffi.Pointer<gameboy_s>, ffi.Uint16, ffi.Uint16)>(symbol: 'GB_cpu_disassemble')
external void cpu_disassemble(ffi.Pointer<gameboy_s> gb, int pc, int count);

It can be manually rewritten to an extension on Pointer:

extension GameboyFfi on ffi.Pointer<gameboy_s> {
  @ffi.Native<ffi.Void Function(ffi.Pointer<gameboy_s>, ffi.Uint16, ffi.Uint16)>(symbol: 'GB_cpu_disassemble')
  external void cpu_disassemble(int pc, int count);
}

Handling this automatically may be out of scope for ffigen, but if it was extensible, someone else would write a package that does this.

szotp avatar May 05 '25 09:05 szotp

IMO it would be better to just make ffigen more customizable. Instead of relying on yaml, provide better support for using ffigen as library:

Possible API:

final config = YamlConfig.fromFile(File('ffigen.yaml')); final customizable = CustomizableConfig(config) customizable.enumClassDecl.customizeRename((x) => x.camelCase); FfiGen().run(customizable)

This is now possible with the Dart API in the 20.0.0 dev release. https://pub.dev/documentation/ffigen/20.0.0-dev.0/ffigen/Functions/renameMember.html you can write arbitrary Dart code.

Closing issue, please re-open if it doesn't work for you.

dcharkes avatar Oct 08 '25 08:10 dcharkes