helix icon indicating copy to clipboard operation
helix copied to clipboard

Formatter doesn't have access to filename

Open IvanGoncharov opened this issue 3 years ago • 30 comments

#2942 added formatter option, which is very useful. I used it prettier but quickly discovered that I have conflicting formatting between CI and my editor.

This happens because prettier change formatting based on filename, e.g. package.json formatted with json-stringify but other *.json files formatted with json parser. https://github.com/prettier/prettier/blob/2316e2fecd171335fc00f3ec97b7e46cc8964153/src/language-js/index.js#L81-L94

To solve this use case, prettier provides --stdin-filepath, but I can't use it in helix since there is no way to pass the filename into fomatter option.

Having a placeholder of some kind would be great, e.g. $filename.

IvanGoncharov avatar Aug 29 '22 11:08 IvanGoncharov

Previously #2942 did implement passing a file path to the formatter, but it was removed since stdin was deemed sufficient. Maybe this use case will change things.

kirawi avatar Aug 31 '22 14:08 kirawi

I have a similar issue too which would be solved if there was a way to pass in the filename to the formatter command.

kvrohit avatar Sep 09 '22 11:09 kvrohit

I also have this issue with prettier. Not sure how to get it to format correctly

JamesMDunn avatar Sep 14 '22 22:09 JamesMDunn

You can manually specify the parser for prettier to use to avoid needing the file name, see https://prettier.io/docs/en/options.html#parser.

E.g.:

[[language]]
name = "typescript"
auto-format = true
formatter = { command = "prettier", args = ["--parser", "typescript"] }

Anthuang avatar Sep 15 '22 14:09 Anthuang

@Anthuang this is hard to use, because the cli programmer know better than you. for prettier, it has flow|babel|babel-flow|babel-ts|typescript|acorn|espree|meriyah|css|less|scss|json|json5|json-stringify|graphql|markdown|mdx|vue|yaml|glimmer|html|angular|lwc parsers

we can not count on a hard coded config to manual calculate the parser to use. this is bad.

ttys3 avatar Oct 14 '22 10:10 ttys3

I got this problem too.

I think provide the full path filename to the formatter is very important.

some formatters need the full file path to help with location a config in the project (stylua) or use it to determine the file type (prettier),

in neovim we can use vim.api.nvim_buf_get_name(0) to get the current buf file path, but in hexlix seems no way to do so.

for example:

style:

--stdin-filepath Specify the location of the file that is being passed into stdin. Ignored if not taking in input from stdin. This option is only used to help determine where to find the configuration file

require("formatter").setup {
	filetype = {
		javascript = {
			-- prettier
			function()
				return {
					exe = "prettier",
					args = { "--stdin-filepath", vim.api.nvim_buf_get_name(0), "--single-quote" },
					stdin = true,
				}
			end,
		},
		lua = {
			-- stylua
			function()
				return {
					exe = "stylua",
					args = { "--search-parent-directories", "--stdin-filepath", vim.api.nvim_buf_get_name(0), "-" },
					stdin = true,
				}
			end,
		},
	}
}

ttys3 avatar Oct 14 '22 10:10 ttys3

Just adding a +1 to this as a Rubocop user. Without a filename, it's impossible to properly configure rules that only apply to (or are only excepted from) certain files and/or directories.

nestor-custodio avatar Dec 19 '22 20:12 nestor-custodio

Reverting https://github.com/helix-editor/helix/pull/2942/commits/f7ecf9c830e1c92a59bb13a11b08a1bb5a7da39e and https://github.com/helix-editor/helix/pull/2942/commits/acdce30bd49405703fcbc0d1012beceb00fbdee7 should add filename formatting.

kirawi avatar Dec 19 '22 21:12 kirawi

clang-format would also benefit from being able to pass the filename.

Icantjuddle avatar Mar 10 '23 17:03 Icantjuddle

eslint cannot format without stdin-filename

vanarok avatar May 26 '23 02:05 vanarok

I think this might be more generally-solved by https://github.com/helix-editor/helix/issues/7105

Or, perhaps, a similar approach to that issue: where there is a general value placeholder system, and an initially-fixed set of values we can refer to from within the TOML configuration file, etc

jokeyrhyme avatar May 26 '23 05:05 jokeyrhyme

I've encountered two cases where this would be useful:

  • clang-format-diff needs to know what file you're editing, so it can apply a relevant section of the diff. This is useful when you want to format new changes in a codebase that is not fully formatted.
  • ~goimports requires a filename, not stdin. I think this is because it needs to know the name of the module when sorting imports.~ I'm wrong, goimports works over stdin.

rcorre avatar Sep 08 '23 21:09 rcorre

I'm using this as a workaround.

formatter = { command = "sh", args = ["-c", """
  file=$(
    ps -p "${PPID}" -o "command=" \
      | awk '{ print $NF }'
  )
  exec prettier \
    --stdin-filepath="${file}" \
    --config-precedence=file-override
"""] }

tynanbe avatar Nov 14 '23 00:11 tynanbe

@tynanbe that will only work if you ran hx some_file, right? If you open a different file within helix, it won't know what the file is.

FWIW, using source.organizeImports with https://github.com/helix-editor/helix/pull/6486#issuecomment-1722306737 means I no longer need to run goimports as a formatter, but this would still be great for clang-format-diff.

rcorre avatar Nov 14 '23 11:11 rcorre

@rcorre, indeed, I haven't tested that use case, but I personally don't use Helix in that way, so not a problem for me :smile:

tynanbe avatar Nov 14 '23 14:11 tynanbe

Usually for clang-format we execute it like this:

clang-format -i --style=file:<configuration file> <source_file>

While <configuration file> is usually always the same and can be hardcoded, <source file> is usually always different and should be absolute path to the file currently being edited in Helix. So we need a file placeholder to a file currently being edited.

71GA avatar Dec 05 '23 07:12 71GA

@71GA you can use plain clang-format with helix currently, as it can communicate over stdin/stdout. clangd also supports formatting if you use that as your language server. Typically I just use clangd for C++ formatting, and clang-format with the --assume-filename flag to format protobuf:

[[language]]
name = "protobuf"
formatter = { command = "clang-format" , args = ["--assume-filename=a.proto"]}

It was specifically clang-format-diff (for partially formatted codebases) that I struggled with.

rcorre avatar Dec 06 '23 16:12 rcorre

To address the original issue, it is possible to create a custom language block for a specific set of files. This can be done by adding the following block to your languages.toml file:

[[language]]
name = "package.json" # this can be set to any string that doesn't conflict with other language names
scope = "source.json"
roots = ["package.json"]
file-types = ["package.json", "package-lock.json", "composer.json"]
formatter = { command = "npx", args = ["prettier", "--stdin-filepath", "package.json"] }
language-servers = ["vscode-json-language-server"]
auto-format = true
grammar = "json"

To get syntax highlighting to work, you also need to copy (or symlink) the runtime/queries/json directory to runtime/queries/package.json.

This seems like the cleanest workaround for now (to me), but I agree that it would be best if helix supported passing the filename to the formatter.

foxcroftjn avatar Dec 13 '23 07:12 foxcroftjn

I have the same problem in Python with Ruff when trying to sort imports. First-party imports are incorrectly categorized as third-party if stdin is used without the --stdin-filename option. This leads to inconsistencies between running Ruff as an auto-format command and as a code action.

bluthej avatar Jan 09 '24 23:01 bluthej

+1 In my case, the path is required by PowerShell-Beautifier

Bobrokus avatar Feb 01 '24 18:02 Bobrokus

This is a mandatory feature, especially when the formatter config file is not at the root.

akhansari avatar Mar 16 '24 00:03 akhansari

@akhansari pestering the maintainers isn’t going to motivate anyone to get it done. If you feel it’s important it might be wise to focus your efforts on writing a PR instead.

zjr avatar Mar 16 '24 02:03 zjr

Just got mugged...

@zjr It wasn't my intention. I wanted to contribute by giving a feedback as a user and to highlight the importance of this feature for formatters usually based on local config files. Nothing else.

And if I had enough time and if I knew rust well, it would have been with pleasure. Could you please give the benefit of doubt next time and not make hasty conclusions. It's toxical for the community. Although English is not main language of many contributers and they can miss some nuances.

akhansari avatar Mar 16 '24 09:03 akhansari