zed-industries / zed

Code at the speed of thought – Zed is a high-performance, multiplayer code editor from the creators of Atom and Tree-sitter.
https://zed.dev
Other
47.62k stars 2.78k forks source link

Eslint/Prettier Support #5612

Closed jamesdbruner closed 11 months ago

jamesdbruner commented 2 years ago

I tried every way I could think of to try to get format_on_save to work with my existing eslint/prettier setup but I can't figure out how to make it work. I have a narwhal monorepo with an eslintrc.json file at the root and one in every project and have it setup to use prettier as the formatter.

In vscode and webstorm they pickup the nearest eslintrc and use those rules to format my file on save since I added these lines to my settings.json

"editor.codeActionsOnSave": {
  "source.fixAll.eslint": true
},

Here's an example of what that root eslintrc.json looks like:

{
  "root": true,
  "plugins": ["@nrwl/nx"],
  "overrides": [
    {
      "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
      "rules": {
        "@nrwl/nx/enforce-module-boundaries": [
          "error",
          {
            "enforceBuildableLibDependency": true,
            "allow": [],
            "depConstraints": [
              {
                "sourceTag": "*",
                "onlyDependOnLibsWithTags": ["*"]
              }
            ]
          }
        ]
      }
    },
    {
      "files": ["*.ts", "*.tsx"],
      "extends": [
        "plugin:@nrwl/nx/typescript",
        "plugin:prettier/recommended"
      ],
      "rules": {
        "prettier/prettier": [
          "warn",
          {
            "semi": false,
            "singleQuote": true,
            "tabs": true,
            "useTabs": true,
            "tabWidth": 1,
            "printWidth": 120,
            "endOfLine": "auto"
          }
        ]
      }
    },
    {
      "files": ["*.js", "*.jsx"],
      "extends": ["plugin:@nrwl/nx/javascript"],
      "rules": {}
    }
  ]
}

Can I use the current format_on_save setting to replicate how vscode or webstorm work in this regard? I'm probably just being dumb but would really appreciate some clarification or direction. Awesome work so far, and if I can get this figured out Zed will likely be my editor of choice for the foreseeable future.

hovsater commented 2 years ago

@jamesdbruner have you seen https://zed.dev/docs/javascript? It showcases an example in which you customize format_on_save to use Prettier instead.

jamesdbruner commented 2 years ago

Yes, I've seen that yes I can get prettier to format my code by doing that. I don't think you should have to install prettier globally when I have it installed at the root of my repository and also I'd prefer to let eslint dictate how and when prettier runs I guess is my point. Is it possible to do something like this?

    "language_overrides": {
        "TypeScript": {
            "format_on_save": {
                "external": {
                    "command": "eslint",
                    "arguments": [
                        "--stdin-filepath",
                        "{buffer_path}",
                        "--fix"
                    ]
                }
            }
        }
    }
as-cii commented 2 years ago

Thanks for the feedback, @jamesdbruner! And thanks @kevinsjoberg for providing support on this! ✨

I don't think you should have to install prettier globally when I have it installed at the root of my repository

This should already be possible, as we run the command from the root of the worktree that you opened. So you should be able to run things like npx or specify a command as a relative path node_modules/.bin/prettier. Does something like this work for you?

"language_overrides": {
    "JavaScript": {
        "format_on_save": {
            "external": {
                "command": "npx", // you could also specify "node_modules/.bin/prettier" here
                "arguments": [
                    "prettier",
                    "--stdin-filepath",
                    "{buffer_path}"
                ]
            }
        }
    }
}

also I'd prefer to let eslint dictate how and when prettier runs I guess is my point.

As for eslint, they support reading files from stdin but I am afraid they don't support reporting the fixed output on stdout. I saw they support reporting fixes as JSON to stdout, so you can probably write a simple script that invokes eslint. I was able to make it work using https://github.com/mantoni/eslint_d.js and the following configuration:

"language_overrides": {
    "JavaScript": {
        "format_on_save": {
            "external": {
                "command": "npx",
                "arguments": [
                    "eslint_d",
                    "--stdin",
                    "--stdin-filename",
                    "{buffer_path}",
                    "--fix-to-stdout"
                ]
            }
        }
    }
}

I understand this is suboptimal and we should probably support a more out-of-the-box experience, but would the above work for you?

jamesdbruner commented 2 years ago

@as-cii Thanks so much for getting back to me! I'll try this tonight and let you know how it goes. Honestly so long as it works, I don't really mind adding configuration and considering how npx works, I believe it'll use my local eslint before reaching out to the web to download it. I think that should be a good solution until something out of the box is released.

fnky commented 2 years ago

I tried this but the experience is not so great. Formatting takes some time since it has to boot up Node each time, and the cursor is moved the the start of the line each time after formatting.

I'm sure this will be solved with user plugins :)

morajabi commented 2 years ago

Should we make another issue about inline ESlint error/warning support? Personally, I'm interested in a language-server-like experience for ESLint similar to the extension for VS Code.

On another note, @fnky is right about prettier being slow when used like this.

uicowboy commented 1 year ago

@morajabi Yeah +1, especially when considering how a lot of enterprise apps are built using Prettier and ESLint together. If these technologies work great out of the box, it will help with Zed's adoption.

Edit: have been using Zed for a few hours now running the formatter using Prettier, since that's what we use for all frontend projects at my company. On every save, there's a noticeable ~1s delay from the moment CMD+S is pressed to when the formatting is done. This is unfortunate, particularly because Zed is fairly speedy and this defeats that enough that it's noticeable all the time.

victororlyk commented 1 year ago

Should we make another issue about inline ESlint error/warning support? Personally, I'm interested in a language-server-like experience for ESLint similar to the extension for VS Code.

On another note, @fnky is right about prettier being slow when used like this.

I have created feature request for that https://github.com/zed-industries/zed/issues/4901

func0x commented 1 year ago

Maybe in here is a great person to told me how I can run this prettier on save with tsx files?

"language_overrides": {
        "TypeScript": {
            "format_on_save": {
                "external": {
                    "command": "node_modules/.bin/prettier", // this or npx and "prettier" as a first arguments
                    "arguments": [
                        "--stdin-filepath",
                        "{buffer_path}"
                    ]
                }
            }
        }
    }

When I use in terminal node_modules/.bin/prettier --write PATH_TO_FILE it's work and I assume to add this "--write" as a first argument to arguments array and to be working but it don't.

I test it changing file extension to JSX and change language in override from TypeScript to JavaScript and then everything works.... but why not work with TS?

gh0stonio commented 1 year ago

Hi everyone,

Thanks to all tips here how I've succeed to format properly my TSX files with both prettier and eslint rules.

Here my eslintrc:

{
    "extends": ["next/core-web-vitals"],
    "plugins": ["arca", "prettier"],
    "rules": {
        "prefer-const": "error",
        "prettier/prettier": "error",
        "arca/import-ordering": [
            "error",
            {
                "sections": [
                    "^~/",
                    "^\\.\\./",
                    "^\\./"
                ]
            }
        ],
        "arca/newline-after-import-section": [
            "error",
            {
                "sections": [
                    "^~/",
                    "^\\.\\./",
                    "^\\./"
                ]
            }
        ]
    }
}

Here my Zed settings:

{
  ...
  "language_overrides": {
        "TypeScript": {
            "format_on_save": {
                "external": {
                    "command": "node_modules/.bin/eslint_d",
                    "arguments": [
                        "--stdin",
                        "--fix",
                        "--fix-to-stdout",
                        "--stdin-filename",
                        "{buffer_path}"
                    ]
                }
            }
        },
        "TSX": {
            "format_on_save": {
                "external": {
                    "command": "node_modules/.bin/eslint_d",
                    "arguments": [
                        "--stdin",
                        "--fix",
                        "--fix-to-stdout",
                        "--stdin-filename",
                        "{buffer_path}"
                    ]
                }
            }
        }
    }
}

I'm using https://github.com/mantoni/eslint_d.js as recommended by @as-cii to be able to handle properly stdin and stdout and an eslint plugin for prettier to apply prettier formatting at the same time.

msdrigg commented 1 year ago

I'm trying out zed and a bit disappointed that my .eslintrc config isn't supported for diagnostics.

My specific use case is that I am developing a next.js project and often rely on eslint warnings to catch react hooks dependency errors. If I run npm run lint to trigger a lint, it correctly detects these errors, but zed does NOT show these warnings in the editor anywhere.

I can even configure the warnings to show up as errors in .eslintrc config and they still don't show up. It appears that .eslintrc is being ignored by zed.

iamnbutler commented 1 year ago

ESLint is very on our radar, and should be tackled soon!

msdrigg commented 1 year ago

I believe eslint is already integrated into typescript-language-server, so in theory my use case should be covered by zed.dev as long as typescript-language-server supports this. I have submitted an issue there as well that may resolve this. I'll update here if anything comes from it https://github.com/typescript-language-server/typescript-language-server/issues/708

msdrigg commented 1 year ago

Wait — I was confused eslint Isnt integration into typescript language server at all

tinchoz49 commented 1 year ago

Wait — I was confused eslint Isnt integration into typescript language server at all

But is integrated here: https://github.com/microsoft/vscode-eslint/tree/main/server so your idea still makes sense. I mean using eslint as a LSP.

janmonschke commented 1 year ago

ESLint is very on our radar, and should be tackled soon!

@iamnbutler Great to hear that it's on your radar 🎉 Is there a way to track progress on planned features?

Rados51 commented 1 year ago

@iamnbutler Would it also be possible to group language_overrides like JavaScript|TypeScript|TSX|JSON instead of writing same config for each lang? Thanks :)

iamnbutler commented 1 year ago

@iamnbutler Would it also be possible to group language_overrides like JavaScript|TypeScript|TSX|JSON instead of writing same config for each lang? Thanks :)

Sounds like a good idea if we can make it work. If there isn't already an issue it would be great if you could create one!

rruzicka-inno commented 1 year ago

Hi everyone,

Thanks to all tips here how I've succeed to format properly my TSX files with both prettier and eslint rules.

Here my eslintrc:

{
    "extends": ["next/core-web-vitals"],
    "plugins": ["arca", "prettier"],
    "rules": {
        "prefer-const": "error",
        "prettier/prettier": "error",
        "arca/import-ordering": [
            "error",
            {
                "sections": [
                    "^~/",
                    "^\\.\\./",
                    "^\\./"
                ]
            }
        ],
        "arca/newline-after-import-section": [
            "error",
            {
                "sections": [
                    "^~/",
                    "^\\.\\./",
                    "^\\./"
                ]
            }
        ]
    }
}

Here my Zed settings:

{
  ...
  "language_overrides": {
        "TypeScript": {
            "format_on_save": {
                "external": {
                    "command": "node_modules/.bin/eslint_d",
                    "arguments": [
                        "--stdin",
                        "--fix",
                        "--fix-to-stdout",
                        "--stdin-filename",
                        "{buffer_path}"
                    ]
                }
            }
        },
        "TSX": {
            "format_on_save": {
                "external": {
                    "command": "node_modules/.bin/eslint_d",
                    "arguments": [
                        "--stdin",
                        "--fix",
                        "--fix-to-stdout",
                        "--stdin-filename",
                        "{buffer_path}"
                    ]
                }
            }
        }
    }
}

I'm using https://github.com/mantoni/eslint_d.js as recommended by @as-cii to be able to handle properly stdin and stdout and an eslint plugin for prettier to apply prettier formatting at the same time.

I used this setup but prettier is not working properly. I have eslint_d installed locally in the project. When I had it globally it didn't work at all. When I changed e.g. quotes to double it didn't do anything.

"format_on_save": {
  "external": {
    "command": "node_modules/.bin/eslint_d",
    "arguments": [
      "--stdin",
      "--fix",
      "--fix-to-stdout",
      "--stdin-filename",
      "{buffer_path}"
    ]
  }
}

When I use this setup it works properly, but eslint --fix doesn't work.

"format_on_save": {
  "external": {
    "command": "node_modules/.bin/prettier",
    "arguments": [
      "--stdin-filepath",
      "{buffer_path}"
    ]
  }
}

And I don't see a way to have both configured, since I can't use an array on command.

slingercode commented 1 year ago

Looking forward for this integration. ATM this is my most anticipated feature and would be awesome when we can have the same interaction as in vscode 👍

vaidotasp commented 1 year ago

this is really needed for any dev work involving web dev, eslint language server support is definitely needed

darcher- commented 1 year ago

Is this really necessary?

The ability to explicitly fine-tune formatting is nice; however, a specific property name to target formatting, linting, etc. seems too granular here. Perhaps a generic approach can grant greater flexibility in this case?

As an aside

I have used the JetBrains Suite, Visual Studios Suite, Notepad/++, Brackets, All the Sublime Text editors, and currently use VSCode as my primary.

There's been quite a few others I've sampled in my career but never got into the "die hard" command line options; My input caters to editors with more interactable interfaces.

So far, I really have enjoyed using Zed and will continue to do so, which is why I'm here today!

Improve the shortcomings in other tools

I see potentially greater gains with an option to enable project-level inheritance, particularly over automatable tasks such as formatting, as a more desirable enhancement. Much of these mundane tasks are being automated with tools like Git Actions or libraries such as lint-staged or husky. This helps abstract non-prod items but it feels short-sighted and hacky, certainly does not resolve the bloat or decouple/abstract tools not required at runtime. I know I have certainly spent entirely too much of my life trying to improve .vscode/settings.json to reduce the footprint of non-prod libraries.

Bridging the gaps

Implementing something that makes those tools obsolete feels like the right goal of an IDE. Taking that a step further, if an IDE can replace any need for devDependencies or peerDependencies in package managers purely by granting the ability to relatively configure these tools you would certainly make a sizable impact on workflows. Perhaps even fully configuring these tools inside of the local .zed/settings.json.

Although everything below contradicts what I just mentioned, I have a few ideas to contribute that may help move toward what I mentioned above in a more succinct and iterative way, maybe...


Root directory assignment

An option to designate root_dir to override/dictate highest level of inheritance... could help narrow the scope for users.

NOTE: perhaps automate reference assignment to a degree?

  1. local "zedings"
    • for configs from .zed/settings.json
    • can likely reference ../node_modules/.bin or ../package.json
  2. default "zedings"
    • for configs from ~/config/zed/settings.json
    • could reference dependencies installed at the "global scope" (e.g. /usr/local)
  3. offer something similar to VSCode's Workspaces or a way to set the root and extend settings into other sub-directories (Something to accommodate monorepo with libraries, apps, & webapp code that may require different options.)
{
  "root_dir": "~/dev/web/%PROJECT_NAME%", // can reach `node_modules` and `package.json`
  "extends": "~/dev/lib/%PROJECT_NAME%" // can reach `.zed/settings.json` to use as default
}

A more generic way to augment on_save events

An option for on_save or additional options for common tasks...

NOTE: I am inept in "all things" pertaining to naming convention.

NOTE: I use Rome as an example as its various use-cases better demonstrate my intentions. The three examples below encapsulate a variety of input formats. All of which, in my eyes, add value.

"on_save": {
  "scope": "project", // local reference
  "plugin": "rome", // runs "node_modules/.bin/rome"
  "command": "check", // runs "rome lint"
  "before": {
    "command": "start", // "rome start"
  },
  "arguments": [
    "--apply", // references "<root_dir>/rome.json"?
    "app", // dir
    "--use-server" // requires "rome start" to execute before, with that in mind, offering the ability to setup callahead/back hooks somehow: `before` & `after` maybe?
  ],
  "after": {
    "command": "stop", // stops server
    "delay": 200
  }
},

Offer various formats to applying configs (and things like arguments)

I'd love to see an IDE with the ability to consume .ya?ml files as configs.

Also, I think for arguments there are a few formats that could grant greater flexibility. Common approaches I've seen in the wild:

NOTE: Regardless of format, ensure RegExp and/or Glob pattern matching works!

Should also, perhaps, allow multiple hooks to execute on_save

"on_save": [
  {
    "scope": "global", // maybe... "global" (e.g. npx) | "project" (e.g. node_modules/.bin/) | "workspace" (e.g. think "monorepo")
    "plugin": "rome", // runs "node_modules/.bin/rome ci"
    "command": "ci", // runs format & lint
    "arguments": {
      "ci": true,
      "configPath": "./config/rome.json", // separate config file
      "applyUnsafe": "**/*.{js,ts}" // glob
    }
  },
  {
    "scope": "project", // local reference
    "plugin": "rome", // runs "node_modules/.bin/rome"
    "command": "check", // runs "rome lint"
    "before": {
      "command": "start", // "rome start"
    },
    "arguments": [
      "--apply", // references "<root_dir>/rome.json"?
      "src", // dir
      "--use-server" // requires "rome start" to execute before, setup a prerquisite hook somehow?
    ],
    "after": {
      "command": "stop", // stops server
      "delay": 200
    }
  },
  {
    "scope": null, // references "generic rome default config" or a CDN?
    "plugin": "rome", // perhaps, with no scope, it attempts "rome" & "npx rome" & "node_modules/.bin/rome"?
    "command": "format", // runs "rome format"
    "arguments": "--write . --colors=off" // regex
  }
],

Closing notes

DISCLAIMER: I do not generally do this... In-fact, this may be my first comment on a public repo, ever.

If by chance, I have done anything that violates any rules or guidelines that I conveniently failed to look for, please leave a note. I will make the necessary adjustments or whatever is required to correct the error.

Lastly, I wrote this sporadically across my work day and only lightly proofed; there may be areas that cause confusion or are repetitive. Feel free to raise anything and I'll add clarity where able if desired.

 

ebg1223 commented 1 year ago

Been following this thread for a while, and am using eslint_d with prettier integration on save. Wanted to share a little trick that someone might find useful:

Use a separate eslint config file for your format on save action, so you still get the benefit of useful errors and warnings while editing, while maintaining integrated prettier on save!

Why / how / if you need details:

prettier advises to keep prettier and eslint separate, primarily because every prettier correction is interpreted as a warning / error while writing code, which can slow things down, and takes away a huge benefit of eslint: to see actual errors and warnings while you are writing. If every line is an error, they are meaningless.

To get around this, while still running eslint fix and prettier on save, use eslint_d, and create a separate .eslintrc.json files(for example, .eslintrc.json, and .eslintrc.withprettier.json).

.eslintrc is detected by zed, so should just have your lint rules you want to see in the editor.

.eslintrc.withprettier.json has all those rules, but also includes prettier:

  "plugins": [
...otherplugins,
    "prettier"
  ],
  "rules": {
    "prettier/prettier": "warn",
    "arrow-body-style": "off",
    "prefer-arrow-callback": "off",
    ...otherRules
}

Then, your formatOnSave settings will call eslint_d using the withprettier config.

  "language_overrides": {
    "TypeScript": {
      "format_on_save": "on",
      "formatter": {
        "external": {
          "command": "node_modules/.bin/eslint_d",
          "arguments": [
            "--config",
            ".eslintrc.withprettier.json",
            "--stdin",
            "--stdin-filename",
            "{buffer_path}",
            "--fix-to-stdout"
          ]
        }
      }
    },
    "JavaScript": {
      "format_on_save": "on",
      "formatter": {
        "external": {
          "command": "node_modules/.bin/eslint_d",
          "arguments": [
            "--config",
            ".eslintrc.withprettier.json",
            "--stdin",
            "--stdin-filename",
            "{buffer_path}",
            "--fix-to-stdout"
          ]
        }
      }
    },
    "TSX": {
      "format_on_save": "on",
      "formatter": {
        "external": {
          "command": "node_modules/.bin/eslint_d",
          "arguments": [
            "--config",
            ".eslintrc.withprettier.json",
            "--stdin",
            "--stdin-filename",
            "{buffer_path}",
            "--fix-to-stdout"
          ]
        }
      }
    }
  }

Just remember, when changing eslint rules, you need to make your changes to both configs. An improvement would probably be to use .eslintrc js files, then the .prettier version would import the standard, add the prettier stuff, and return a new config with prettier included. But for those of us not constantly updating our eslint rules, this works fine!

In practice, only real errors warnings are visible while editing, running a fix on one of them works well without editing formatting, and on each save, everything is fixed and formatted almost instantly!!

apostoiis commented 1 year ago

Wow this is what holds me back from using Zed! @ebg1223 but, I'm a bit confused about what to do, can you please elaborate more on these steps? Let's say I have these settings on a repository (I think it's from work). I have a .eslintrc.js file (has some path configs for graphql schema that's why the .js extension) and a .prettierc.json.

.eslintrc.js

const path = require('path');

const graphqlConfig = {
  env: 'apollo',
  schemaJsonFilepath: path.resolve(__dirname, './src/graphql/schema.json'),
};

module.exports = {
  env: {
    browser: true,
    commonjs: true,
    es6: true,
    node: true,
    jest: true,
    'jest/globals': true,
  },
  extends: [
    ....
  ],
  parser: '@typescript-eslint/parser',
  plugins: [
    ....
    'no-relative-import-paths',
    'prettier', <----
    'react',
    'react-hooks',
    'testing-library',
    .....
  ],
  rules: {
    .....
    'prettier/prettier': ['error'], <----
    'react/destructuring-assignment': 0,
    'react/prop-types': "off",
    .....
  },
  globals: {
     .....
  },
  settings: {
    'import/resolver': {
      typescript: {},
      node: {
        paths: ['src'],
        extensions: ['.js', '.jsx', '.ts', '.tsx', '.d.ts', '.graphql'],
      },
    },
  },
};

.prettier.json

{
  "printWidth": 120,
  "singleQuote": true,
  "trailingComma": "all",
  "bracketSpacing": true
}

Here, prettier is inside the rules of eslint and I have installed eslint_d globally. Should I use a copy of that somewhere and use that file in Zed settings? (sorry if that doesn't make any sense :P)

zed settings

{
  "theme": "Gruvbox Light Soft",
  "show_copilot_suggestions": false,
  "base_keymap": "Atom",
  "buffer_font_size": 15,
  "buffer_font_family": "FuraMono Nerd Font",
  "format_on_save": "on",
  "lsp": {
    "typescript-language-server": {
      "initialization_options": {
        "preferences": {
          "includeInlayParameterNameHints": "all",
          "includeInlayParameterNameHintsWhenArgumentMatchesName": true,
          "includeInlayFunctionParameterTypeHints": true,
          "includeInlayVariableTypeHints": true,
          "includeInlayVariableTypeHintsWhenTypeMatchesName": false,
          "includeInlayPropertyDeclarationTypeHints": true,
          "includeInlayFunctionLikeReturnTypeHints": true,
          "includeInlayEnumMemberValueHints": true
        }
      }
    }
  },
  "language_overrides": {
    "TypeScript": {
      "format_on_save": "on",
      "formatter": {
        "external": {
          "command": "node_modules/.bin/eslint_d",
          "arguments": [
            "--config",
            ".eslintrc.js",
            "--stdin",
            "--stdin-filename",
            "{buffer_path}",
            "--fix-to-stdout"
          ]
        }
      }
    },
    "JavaScript": {
      "format_on_save": "on",
      "formatter": {
        "external": {
          "command": "node_modules/.bin/eslint_d",
          "arguments": [
            "--config",
            ".eslintrc.js",
            "--stdin",
            "--stdin-filename",
            "{buffer_path}",
            "--fix-to-stdout"
          ]
        }
      }
    },
    "TSX": {
      "format_on_save": "on",
      "formatter": {
        "external": {
          "command": "node_modules/.bin/eslint_d",
          "arguments": [
            "--config",
            ".eslintrc.js",
            "--stdin",
            "--stdin-filename",
            "{buffer_path}",
            "--fix-to-stdout"
          ]
        }
      }
    }
  },
}
hyoban commented 1 year ago

Maybe a config like eslint.workingDirectories is great for using eslint in monorepo

nikitavoloboev commented 1 year ago

Zed team can also use https://dprint.dev

It's written in Rust and does same thing as Prettier too.

JosephTLyons commented 1 year ago

Zed team can also use https://dprint.dev

It's written in Rust and does same thing as Prettier too.

Oooh, this is a neat suggestion - thanks for pointing it out @nikitavoloboev.

korywka commented 1 year ago

with this config zed anyway use spaces instead of tabs:

  "hard_tabs": true,
  "tab_size": 2,
  "language_overrides": {
    "JavaScript": {
      "hard_tabs": true,
      "tab_size": 2
    }
  }

native autofixing eslint on save is very desirable feaure.

other options like dprint are good for solo developers, but javascript industry standard is eslint and/or prettier.

smastrom commented 1 year ago

For anyone experiencing performance issues with prettier (it's slow and takes more than expected to format), you can use prettierd:

brew install fsouza/prettierd/prettierd

Make sure its command path is correct:

which prettierd

And set it:

{
  "formatter": {
    "external": {
      "command": "/opt/homebrew/bin/prettierd",
      "arguments": [
        "--stdin-filepath",
        "{buffer_path}"
      ]
    }
  }
}

I already use it on Sublime and it's a great jsPrettier replacement.

nikitavoloboev commented 1 year ago

@smastrom

Doesn't your setting

{
  "formatter": {
    "external": {
      "command": "/opt/homebrew/bin/prettierd",
      "arguments": [
        "--stdin-filepath",
        "{buffer_path}"
      ]
    }
  }
}

Should say that it should only apply the formatter on specific file types only? I assume with above setting it would run even on .rs files which doesn't make sense.

ijsnow commented 11 months ago

I opened up Zed again for the first time in a while and was excited to see the huge improvements and was ready to switch to it for my day to day work until I realized this still isn't resolved. None of the solutions in this thread work for me. Could we please get some official documentation or a timeline for a more complete solution? My setup is a very common one using eslint with the prettier plugin. In 2023 I can't find myself working without a formatter in my workflow :(

joacimguldskog commented 11 months ago

Saw Zed on X, if no formatting it's a no. Can't collab with the team.

BasixKOR commented 11 months ago

For those who'd like to test things out, the current Zed Preview comes with Prettier support.

acusti commented 11 months ago

@BasixKOR do you or anyone from the team know how zed preview determines what files to format with prettier? i removed my existing "formatter" config from settings.json, and one project i have that has a .prettierrc file had prettier format on save working out-of-the-box, while another project i have isn’t doing any format on save. it does have prettier in its package.json and the prettier config in package.json as well, so i tried extracting the config into a separate .prettierrc file and restarted the editor and still no luck.

my best guess is that the issue stems from the second project being a yarn PnP project (v3.6.3), and so not having a node_modules folder. maybe zed is expecting to find the executable for prettier there? maybe i should create a new issue specifically for prettier support on yarn > v2 (and pnpm) projects?

Stanzilla commented 11 months ago

For those who'd like to test things out, the current Zed Preview comes with Prettier support.

it's in stable now, tested today, seems like it ignores my Prettier config, at least the tab indent setting. ESLint support is still broken because it does not support monorepos properly.

JosephTLyons commented 11 months ago

cc: @SomeoneToIgnore ^

SomeoneToIgnore commented 11 months ago

@Stanzilla , you can do debug: open language server logs and select the prettier to see what exactly it uses (including the RPC requests) to debug it better.

In general, it's either the project's prettier (from project's node_modules) that's being used, or the "default" one if no prettier was found on the project. In the former case, it tries to search the config in the project's files, otherwise it composes its own config from Zed's settings (including the tab size) and from prettier field of Zed's config.

Looks like you're hitting the latter case, but I have zero clues what you project is and where your config is.

Stanzilla commented 11 months ago

@Stanzilla , you can do debug: open language server logs and select the prettier to see what exactly it uses (including the RPC requests) to debug it better.

In general, it's either the project's prettier (from project's node_modules) that's being used, or the "default" one if no prettier was found on the project. In the former case, it tries to search the config in the project's files, otherwise it composes its own config from Zed's settings (including the tab size) and from prettier field of Zed's config.

Looks like you're hitting the latter case, but I have zero clues what you project is and where your config is.

there is no prettier in there for me. I'm on 0.109.2

SomeoneToIgnore commented 11 months ago

Which means it did not start for some reason, editor logs may help with that.

Alas, I cannot help you with anything beyond this point without a project and reproduction steps.

Stanzilla commented 11 months ago

Which means it did not start for some reason, editor logs may help with that.

Alas, I cannot help you with anything beyond this point without a project and reproduction steps.

i used https://github.com/WeakAuras/WeakAuras-Companion as a test, which files does it check for to know if it has to start?

SomeoneToIgnore commented 11 months ago
image

Seems to work for me and picking the correct config (judging by the tab size at least). I've git clone'd the project, did pnpm install, opened a file on the screenshot, tabbed it and reformatted. So, again, curious to know your reproduction steps to break it. Any particular file it does not work with?

which files does it check for to know if it has to start?

There are numerous checks, which start with the "web" files that have the languages applicable for prettier: JavaScript, TypeScript, Json, etc. Then, it walks up from every file being formatted up until the project's root and looks for node_modules/package.json and tries to locate prettier (there's more checks and exclusions, the logic pretty much repeats https://github.com/prettier/prettier-vscode). The config lookup is done by prettier itself, pretty much in the same, ascend-from-the-file-to-root, manner.

Stanzilla commented 11 months ago
image

Seems to work for me and picking the correct config (judging by the tab size at least). I've git clone'd the project, did pnpm install, opened a file on the screenshot, tabbed it and reformatted. So, again, curious to know your reproduction steps to break it. Any particular file it does not work with?

which files does it check for to know if it has to start?

There are numerous checks, which start with the "web" files that have the languages applicable for prettier: JavaScript, TypeScript, Json, etc. Then, it walks up from every file being formatted up until the project's root and looks for node_modules/package.json and tries to locate prettier (there's more checks and exclusions, the logic pretty much repeats prettier/prettier-vscode). The config lookup is done by prettier itself, pretty much in the same, ascend-from-the-file-to-root, manner.

Interesting, I did the same steps minus the cloning and the install because I already had it. Used the same ts file as in your screenshot, changed formatting, saved it, it was formatted but no prettier in the logs.

then tried a .vue file, hit save and it was formatted as well, with the wrong spacing here (4 instead of 2 spaces), no prettier in the logs and vue server logs being empty and eslint server logs only showing that it was loaded

SomeoneToIgnore commented 11 months ago

Could it be that you have custom formatter settings?

// How to perform a buffer format. This setting can take two values:
//
// 1. Format code using the current language server:
//     "formatter": "language_server"
// 2. Format code using an external command:
//     "formatter": {
//       "external": {
//         "command": "prettier",
//         "arguments": ["--stdin-filepath", "{buffer_path}"]
//       }
//     }
// 3. Format code using Zed's Prettier integration:
//     "formatter": "prettier"
// 4. Default. Format files using Zed's Prettier integration (if applicable),
//    or falling back to formatting via language server:
//     "formatter": "auto"
"formatter": "auto",

To use prettier, either auto (the new default) or prettier values need to be used for the formatter key.

If not, time to look at the editor logs: zed: open log action could help with that, or straight opening ~/Library/Logs/Zed/Zed.log will do.

Stanzilla commented 11 months ago

My settings (I don't think I ever touched the formatter section):

// Zed settings
//
// For information on how to configure Zed, see the Zed
// documentation: https://zed.dev/docs/configuring-zed
//
// To see all of Zed's default settings without changing your
// custom settings, run the `open default settings` command
// from the command palette or from `Zed` application menu.
{
  "base_keymap": "VSCode",
  "theme": "Ayu Dark",
  "buffer_font_size": 15,
  "soft_wrap": "editor_width",
  "cursor_blink": false,
  "project_panel": {
    // Default width of the project panel.
    "default_width": 240,
    // Where to dock project panel. Can be 'left' or 'right'.
    "dock": "left",
    // Whether to show file icons in the project panel.
    "file_icons": true,
    // Whether to show folder icons or chevrons for directories in the project panel.
    "folder_icons": true,
    // Whether to show the git status in the project panel.
    "git_status": true,
    // Amount of indentation for nested items.
    "indent_size": 8
  },
  "collaboration_panel": {
    // Whether to show the collaboration panel button in the status bar.
    "button": false,
    // Where to dock channels panel. Can be 'left' or 'right'.
    "dock": "left",
    // Default width of the channels panel.
    "default_width": 240
  },
  "assistant": {
    // Whether to show the assistant panel button in the status bar.
    "button": false,
    // Where to dock the assistant. Can be 'left', 'right' or 'bottom'.
    "dock": "right",
    // Default width when the assistant is docked to the left or right.
    "default_width": 640,
    // Default height when the assistant is docked to the bottom.
    "default_height": 320
  },
  // Whether the screen sharing icon is shown in the os status bar.
  "show_call_status_icon": true,
  // Whether to use language servers to provide code intelligence.
  "enable_language_server": true,
  // When to automatically save edited buffers. This setting can
  // take four values.
  //
  // 1. Never automatically save:
  //     "autosave": "off",
  // 2. Save when changing focus away from the Zed window:
  //     "autosave": "on_window_change",
  // 3. Save when changing focus away from a specific buffer:
  //     "autosave": "on_focus_change",
  // 4. Save when idle for a certain amount of time:
  //     "autosave": { "after_delay": {"milliseconds": 500} },
  "autosave": "off",
  // Settings related to the editor's tabs
  "tabs": {
    // Show git status colors in the editor tabs.
    "git_status": false,
    // Position of the close button on the editor tabs.
    "close_position": "right"
  },
  // Whether or not to remove any trailing whitespace from lines of a buffer
  // before saving it.
  "remove_trailing_whitespace_on_save": true,
  // Whether to start a new line with a comment when a previous line is a comment as well.
  "extend_comment_on_newline": true,
  // Whether or not to ensure there's a single newline at the end of a buffer
  // when saving it.
  "ensure_final_newline_on_save": true,
  // Whether or not to perform a buffer format before saving
  "format_on_save": "on",
  // How to perform a buffer format. This setting can take two values:
  //
  // 1. Format code using the current language server:
  //     "formatter": "language_server"
  // 2. Format code using an external command:
  //     "formatter": {
  //       "external": {
  //         "command": "prettier",
  //         "arguments": ["--stdin-filepath", "{buffer_path}"]
  //       }
  //     }
  "formatter": "language_server",
  // How to soft-wrap long lines of text. This setting can take
  // three values:
  //
  // 1. Do not soft wrap.
  //      "soft_wrap": "none",
  // 2. Soft wrap lines that overflow the editor:
  //      "soft_wrap": "editor_width",
  // 3. Soft wrap lines at the preferred line length
  //      "soft_wrap": "preferred_line_length",
  // The column at which to soft-wrap lines, for buffers where soft-wrap
  // is enabled.
  "preferred_line_length": 80,
  // Whether to indent lines using tab characters, as opposed to multiple
  // spaces.
  "hard_tabs": false,
  // How many columns a tab should occupy.
  "tab_size": 4,
  // Control what info is collected by Zed.
  "telemetry": {
    // Send debug info like crash reports.
    "diagnostics": true,
    // Send anonymized usage data like what languages you're using Zed with.
    "metrics": true
  },
  // Automatically update Zed
  "auto_update": true,
  // Git gutter behavior configuration.
  "git": {
    // Control whether the git gutter is shown. May take 2 values:
    // 1. Show the gutter
    //      "git_gutter": "tracked_files"
    // 2. Hide the gutter
    //      "git_gutter": "hide"
    "git_gutter": "tracked_files"
  },
  "copilot": {
    // The set of glob patterns for which copilot should be disabled
    // in any matching file.
    "disabled_globs": [
      ".env"
    ]
  },
  // Settings specific to journaling
  "journal": {
    // The path of the directory where journal entries are stored
    "path": "~",
    // What format to display the hours in
    // May take 2 values:
    // 1. hour12
    // 2. hour24
    "hour_format": "hour12"
  },
  // Settings specific to the terminal
  "terminal": {
    // What shell to use when opening a terminal. May take 3 values:
    // 1. Use the system's default terminal configuration in /etc/passwd
    //      "shell": "system"
    // 2. A program:
    //      "shell": {
    //        "program": "sh"
    //      }
    // 3. A program with arguments:
    //     "shell": {
    //         "with_arguments": {
    //           "program": "/bin/bash",
    //           "arguments": ["--login"]
    //         }
    //     }
    "shell": "system",
    // Where to dock terminals panel. Can be 'left', 'right', 'bottom'.
    "dock": "bottom",
    // Default width when the terminal is docked to the left or right.
    "default_width": 640,
    // Default height when the terminal is docked to the bottom.
    "default_height": 320,
    // What working directory to use when launching the terminal.
    // May take 4 values:
    // 1. Use the current file's project directory.  Will Fallback to the
    //    first project directory strategy if unsuccessful
    //      "working_directory": "current_project_directory"
    // 2. Use the first project in this workspace's directory
    //      "working_directory": "first_project_directory"
    // 3. Always use this platform's home directory (if we can find it)
    //     "working_directory": "always_home"
    // 4. Always use a specific directory. This value will be shell expanded.
    //    If this path is not a valid directory the terminal will default to
    //    this platform's home directory  (if we can find it)
    //      "working_directory": {
    //        "always": {
    //          "directory": "~/zed/projects/"
    //        }
    //      }
    //
    //
    "working_directory": "current_project_directory",
    // Set the cursor blinking behavior in the terminal.
    // May take 4 values:
    //  1. Never blink the cursor, ignoring the terminal mode
    //         "blinking": "off",
    //  2. Default the cursor blink to off, but allow the terminal to
    //     set blinking
    //         "blinking": "terminal_controlled",
    //  3. Always blink the cursor, ignoring the terminal mode
    //         "blinking": "on",
    "blinking": "terminal_controlled",
    // Set whether Alternate Scroll mode (code: ?1007) is active by default.
    // Alternate Scroll mode converts mouse scroll events into up / down key
    // presses when in the alternate screen (e.g. when running applications
    // like vim or  less). The terminal can still set and unset this mode.
    // May take 2 values:
    //  1. Default alternate scroll mode to on
    //         "alternate_scroll": "on",
    //  2. Default alternate scroll mode to off
    //         "alternate_scroll": "off",
    "alternate_scroll": "off",
    // Set whether the option key behaves as the meta key.
    // May take 2 values:
    //  1. Rely on default platform handling of option key, on macOS
    //     this means generating certain unicode characters
    //         "option_to_meta": false,
    //  2. Make the option keys behave as a 'meta' key, e.g. for emacs
    //         "option_to_meta": true,
    "option_as_meta": false,
    // Whether or not selecting text in the terminal will automatically
    // copy to the system clipboard.
    "copy_on_select": false,
    // Any key-value pairs added to this list will be added to the terminal's
    // environment. Use `:` to separate multiple values.
    "env": {
      // "KEY": "value1:value2"
    },
    // Set the terminal's line height.
    // May take 3 values:
    //  1. Use a line height that's comfortable for reading, 1.618
    //         "line_height": "comfortable"
    //  2. Use a standard line height, 1.3. This option is useful for TUIs,
    //      particularly if they use box characters
    //         "line_height": "standard",
    //  3. Use a custom line height.
    //         "line_height": {
    //           "custom": 2
    //         },
    "line_height": "comfortable"
    // Set the terminal's font size. If this option is not included,
    // the terminal will default to matching the buffer's font size.
    // "font_size": "15"
    // Set the terminal's font family. If this option is not included,
    // the terminal will default to matching the buffer's font family.
    // "font_family": "Zed Mono"
  },
  // Difference settings for semantic_index
  "semantic_index": {
    "enabled": false,
    "reindexing_delay_seconds": 600
  },
  // Different settings for specific languages.
  "languages": {
    "Plain Text": {
      "soft_wrap": "preferred_line_length"
    },
    "Elixir": {
      "tab_size": 2
    },
    "Go": {
      "tab_size": 4,
      "hard_tabs": true
    },
    "Markdown": {
      "soft_wrap": "preferred_line_length"
    },
    "JavaScript": {
      "tab_size": 2
    },
    "TypeScript": {
      "tab_size": 2
    },
    "TSX": {
      "tab_size": 2
    },
    "YAML": {
      "tab_size": 2
    },
    "JSON": {
      "tab_size": 2
    }
  },
  // LSP Specific settings.
  "lsp": {
    // Specify the LSP name as a key here.
    // "rust-analyzer": {
    //     //These initialization options are merged into Zed's defaults
    //     "initialization_options": {
    //         "checkOnSave": {
    //             "command": "clippy"
    //         }
    //     }
    // }
  }
}
SomeoneToIgnore commented 11 months ago

"formatter": "language_server",

Either touched or not, this is the culprit. I suggest using "auto" instead of the "language_server" value.

Stanzilla commented 11 months ago

logs:

2023-10-26T13:42:53 [INFO] Node runtime install_if_needed
2023-10-26T13:42:53 [INFO] Fetching default prettier and plugins: [("prettier", "3.0.3")]
2023-10-26T13:42:53 [INFO] Node runtime install_if_needed
2023-10-26T13:42:53 [ERROR] Failed to create prettier instance for buffer during autoformatting: prettier start: no prettier server package found at "/Users/stan/Library/Application Support/Zed/prettier/prettier_server.js"
2023-10-26T13:42:55 [INFO] 12 unhandled notification eslint/status:
{
  "uri": "file:///Users/stan/projects/personal/WeakAuras-Companion/src/libs/build-account-list.ts",
  "state": 1
}
2023-10-26T13:42:56 [ERROR] Failed to create prettier instance for buffer during autoformatting: prettier start: no prettier server package found at "/Users/stan/Library/Application Support/Zed/prettier/prettier_server.js"
2023-10-26T13:42:56 [INFO] 10 unhandled notification eslint/status:
{
  "uri": "file:///Users/stan/projects/personal/WeakAuras-Companion/src/libs/build-account-list.ts",
  "state": 1
}
Stanzilla commented 11 months ago

"formatter": "language_server",

Either touched or not, this is the culprit. I suggest using "auto" instead of the "language_server" value.

Yup, looks like it, had to restart Zed for it to take effect but now it shows up in the lsp logs! Thanks!

SomeoneToIgnore commented 11 months ago

Great, let's close this as done then, thank you for testing it on another project. Please open new issues for future related bugs.

Stanzilla commented 11 months ago

What does it use for format .vue files atm? Can't really tell from the logs

SomeoneToIgnore commented 11 months ago

IIRC, it should fall back to language server formatting with that "formatter": "auto" setting.