lassik / emacs-format-all-the-code

Auto-format source code in many languages with one command
https://melpa.org/#/format-all
MIT License
610 stars 106 forks source link

Implement "format region" feature for formatters without native support #17

Closed diamond-lizard closed 3 years ago

diamond-lizard commented 5 years ago

Is there any chance you could provide a format-all-region command?

It's be nice to be able to reformat a region without having to reformat absolutely everything.

lassik commented 5 years ago

I don't know how well the formatters work with partial source code (mainly with regards to indentation) but we can try it. E.g. Emacs' built-in indent-region function can read the full source file so it can still indent correctly even if you tell it to indent only a part of it. The external formatter would only get the region and think it's the whole file. I don't recall any of them having a command line flag to only format a region.

lassik commented 5 years ago

Most of the formatters can be run manually from Emacs via C-u M-x shell-command-on-region. For example, select a region of C/Java code, then do C-u M-x shell-command-on-region clang-format. Please try this for the languages you are interested in to see if you think the result is sensible. A format-all-region command would essentially do the same thing, just more convenient. I tried it on some nested C code and as expected, it loses the indentation.

lassik commented 5 years ago

swiftformat has a --fragment switch to format partial files but that's the only one I can find that has native support.

lassik commented 5 years ago

clang-format has support:

-offset= int

Format a range starting at this byte offset. Multiple ranges can be formatted by specifying several -offset and -length pairs. Can only be used with one input file.

-length= int

Format a range of this length (in bytes). Multiple ranges can be formatted by specifying several -offset and -length pairs. When only a single -offset is specified without -length, clang-format will format up to the end of the file. Can only be used with one input file.

lassik commented 5 years ago

prettier has support too:

Editor options:

--cursor-offset int

Print (to stderr) where a cursor at the given position would move to after formatting. This option cannot be used with --range-start and --range-end. Defaults to -1.

--range-end int

Format code ending at a given character offset (exclusive). The range will extend forwards to the end of the selected statement. This option cannot be used with --cursor-offset. Defaults to Infinity.

--range-start int

Format code starting at a given character offset. The range will extend backwards to the start of the first line containing the selected statement. This option cannot be used with --cursor-offset. Defaults to 0.

c02y commented 3 years ago

Is it able to only format the modified part, not the whole buffer? This feature is very useful when you edit other people's code, and they use different code styles, it is better to only format the code of your own.

Of course, this feature can be provided by variable and command.

lassik commented 3 years ago

Unfortunately it can't do that - the whole buffer is formatted every time. The rationale is given in the above comments: it's hard to do reliably.

As a workaround, you can create a temporary buffer that is not saved into a file (by switching into any buffer whose name does not yet exist), paste a code snippet there, switch to the mode you want (e.g. M-x c-mode, M-x js-mode and so on), and then do M-x format-all-buffer and copy back the formatted text to the original file.

drcxd commented 3 years ago

Actually, this problem can be workaround by executing the command narrow-to-region to make emacs create a temporary buffer which holds the region you want to format. Then in the temporary buffer, execute format-all-buffer. The result is that in the original buffer, only the selected region is formatted.

lassik commented 3 years ago

narrow-to-region doesn't solve the indentation problem. If you have particular formatters that you'd like to use to format regions, please ask the maintainers of those formatters if they could add an official command line option for the job (like prettier has done). That would solve the problem properly for all editor plugins, not only format-all.

I'll be happy to add support for those command line options to format-all (in fact, support for the prettier, clang-format, and swift-format flags should already be added; thanks for the reminder).

lassik commented 3 years ago

Closing this since #150 now implements M-x format-all-region for formatters that support it natively. For formatters without native support, I'll be happy to help explain to their authors what kind of command line flags are needed.