.zed/settings.json 🔗
@@ -15,6 +15,10 @@
"JSON": {
"tab_size": 2,
"formatter": "prettier"
+ },
+ "JavaScript": {
+ "tab_size": 2,
+ "formatter": "prettier"
}
},
"formatter": "auto"
Thorsten Ball created
This PURELY formats the file by opening it in Zed and hitting save with
save-on-format on.
It's been bugging me that I can't change the file without the whole
thing getting reformatted, so here we are.
Release Notes:
- N/A
.zed/settings.json | 4
crates/prettier/src/prettier_server.js | 412 ++++++++++++++-------------
2 files changed, 221 insertions(+), 195 deletions(-)
@@ -15,6 +15,10 @@
"JSON": {
"tab_size": 2,
"formatter": "prettier"
+ },
+ "JavaScript": {
+ "tab_size": 2,
+ "formatter": "prettier"
}
},
"formatter": "auto"
@@ -5,241 +5,263 @@ const { once } = require("events");
const prettierContainerPath = process.argv[2];
if (prettierContainerPath == null || prettierContainerPath.length == 0) {
- process.stderr.write(
- `Prettier path argument was not specified or empty.\nUsage: ${process.argv[0]} ${process.argv[1]} prettier/path\n`,
- );
- process.exit(1);
+ process.stderr.write(
+ `Prettier path argument was not specified or empty.\nUsage: ${process.argv[0]} ${process.argv[1]} prettier/path\n`,
+ );
+ process.exit(1);
}
fs.stat(prettierContainerPath, (err, stats) => {
- if (err) {
- process.stderr.write(`Path '${prettierContainerPath}' does not exist\n`);
- process.exit(1);
- }
+ if (err) {
+ process.stderr.write(`Path '${prettierContainerPath}' does not exist\n`);
+ process.exit(1);
+ }
- if (!stats.isDirectory()) {
- process.stderr.write(`Path '${prettierContainerPath}' exists but is not a directory\n`);
- process.exit(1);
- }
+ if (!stats.isDirectory()) {
+ process.stderr.write(
+ `Path '${prettierContainerPath}' exists but is not a directory\n`,
+ );
+ process.exit(1);
+ }
});
const prettierPath = path.join(prettierContainerPath, "node_modules/prettier");
class Prettier {
- constructor(path, prettier, config) {
- this.path = path;
- this.prettier = prettier;
- this.config = config;
- }
+ constructor(path, prettier, config) {
+ this.path = path;
+ this.prettier = prettier;
+ this.config = config;
+ }
}
(async () => {
- let prettier;
- let config;
- try {
- prettier = await loadPrettier(prettierPath);
- config = (await prettier.resolveConfig(prettierPath)) || {};
- } catch (e) {
- process.stderr.write(`Failed to load prettier: ${e}\n`);
- process.exit(1);
- }
- process.stderr.write(`Prettier at path '${prettierPath}' loaded successfully, config: ${JSON.stringify(config)}\n`);
- process.stdin.resume();
- handleBuffer(new Prettier(prettierPath, prettier, config));
+ let prettier;
+ let config;
+ try {
+ prettier = await loadPrettier(prettierPath);
+ config = (await prettier.resolveConfig(prettierPath)) || {};
+ } catch (e) {
+ process.stderr.write(`Failed to load prettier: ${e}\n`);
+ process.exit(1);
+ }
+ process.stderr.write(
+ `Prettier at path '${prettierPath}' loaded successfully, config: ${JSON.stringify(config)}\n`,
+ );
+ process.stdin.resume();
+ handleBuffer(new Prettier(prettierPath, prettier, config));
})();
async function handleBuffer(prettier) {
- for await (const messageText of readStdin()) {
- let message;
- try {
- message = JSON.parse(messageText);
- } catch (e) {
- sendResponse(makeError(`Failed to parse message '${messageText}': ${e}`));
- continue;
- }
- // allow concurrent request handling by not `await`ing the message handling promise (async function)
- handleMessage(message, prettier).catch((e) => {
- const errorMessage = message;
- if ((errorMessage.params || {}).text !== undefined) {
- errorMessage.params.text = "..snip..";
- }
- sendResponse({
- id: message.id,
- ...makeError(`error during message '${JSON.stringify(errorMessage)}' handling: ${e}`),
- });
- });
+ for await (const messageText of readStdin()) {
+ let message;
+ try {
+ message = JSON.parse(messageText);
+ } catch (e) {
+ sendResponse(makeError(`Failed to parse message '${messageText}': ${e}`));
+ continue;
}
+ // allow concurrent request handling by not `await`ing the message handling promise (async function)
+ handleMessage(message, prettier).catch((e) => {
+ const errorMessage = message;
+ if ((errorMessage.params || {}).text !== undefined) {
+ errorMessage.params.text = "..snip..";
+ }
+ sendResponse({
+ id: message.id,
+ ...makeError(
+ `error during message '${JSON.stringify(errorMessage)}' handling: ${e}`,
+ ),
+ });
+ });
+ }
}
const headerSeparator = "\r\n";
const contentLengthHeaderName = "Content-Length";
async function* readStdin() {
- let buffer = Buffer.alloc(0);
- let streamEnded = false;
- process.stdin.on("end", () => {
- streamEnded = true;
- });
- process.stdin.on("data", (data) => {
- buffer = Buffer.concat([buffer, data]);
- });
+ let buffer = Buffer.alloc(0);
+ let streamEnded = false;
+ process.stdin.on("end", () => {
+ streamEnded = true;
+ });
+ process.stdin.on("data", (data) => {
+ buffer = Buffer.concat([buffer, data]);
+ });
- async function handleStreamEnded(errorMessage) {
- sendResponse(makeError(errorMessage));
- buffer = Buffer.alloc(0);
- messageLength = null;
- await once(process.stdin, "readable");
- streamEnded = false;
- }
+ async function handleStreamEnded(errorMessage) {
+ sendResponse(makeError(errorMessage));
+ buffer = Buffer.alloc(0);
+ messageLength = null;
+ await once(process.stdin, "readable");
+ streamEnded = false;
+ }
- try {
- let headersLength = null;
- let messageLength = null;
- main_loop: while (true) {
- if (messageLength === null) {
- while (buffer.indexOf(`${headerSeparator}${headerSeparator}`) === -1) {
- if (streamEnded) {
- await handleStreamEnded("Unexpected end of stream: headers not found");
- continue main_loop;
- } else if (buffer.length > contentLengthHeaderName.length * 10) {
- await handleStreamEnded(
- `Unexpected stream of bytes: no headers end found after ${buffer.length} bytes of input`,
- );
- continue main_loop;
- }
- await once(process.stdin, "readable");
- }
- const headers = buffer
- .subarray(0, buffer.indexOf(`${headerSeparator}${headerSeparator}`))
- .toString("ascii");
- const contentLengthHeader = headers
- .split(headerSeparator)
- .map((header) => header.split(":"))
- .filter((header) => header[2] === undefined)
- .filter((header) => (header[1] || "").length > 0)
- .find((header) => (header[0] || "").trim() === contentLengthHeaderName);
- const contentLength = (contentLengthHeader || [])[1];
- if (contentLength === undefined) {
- await handleStreamEnded(`Missing or incorrect ${contentLengthHeaderName} header: ${headers}`);
- continue main_loop;
- }
- headersLength = headers.length + headerSeparator.length * 2;
- messageLength = parseInt(contentLength, 10);
- }
-
- while (buffer.length < headersLength + messageLength) {
- if (streamEnded) {
- await handleStreamEnded(
- `Unexpected end of stream: buffer length ${buffer.length} does not match expected header length ${headersLength} + body length ${messageLength}`,
- );
- continue main_loop;
- }
- await once(process.stdin, "readable");
- }
-
- const messageEnd = headersLength + messageLength;
- const message = buffer.subarray(headersLength, messageEnd);
- buffer = buffer.subarray(messageEnd);
- headersLength = null;
- messageLength = null;
- yield message.toString("utf8");
+ try {
+ let headersLength = null;
+ let messageLength = null;
+ main_loop: while (true) {
+ if (messageLength === null) {
+ while (buffer.indexOf(`${headerSeparator}${headerSeparator}`) === -1) {
+ if (streamEnded) {
+ await handleStreamEnded(
+ "Unexpected end of stream: headers not found",
+ );
+ continue main_loop;
+ } else if (buffer.length > contentLengthHeaderName.length * 10) {
+ await handleStreamEnded(
+ `Unexpected stream of bytes: no headers end found after ${buffer.length} bytes of input`,
+ );
+ continue main_loop;
+ }
+ await once(process.stdin, "readable");
}
- } catch (e) {
- sendResponse(makeError(`Error reading stdin: ${e}`));
- } finally {
- process.stdin.off("data", () => {});
+ const headers = buffer
+ .subarray(0, buffer.indexOf(`${headerSeparator}${headerSeparator}`))
+ .toString("ascii");
+ const contentLengthHeader = headers
+ .split(headerSeparator)
+ .map((header) => header.split(":"))
+ .filter((header) => header[2] === undefined)
+ .filter((header) => (header[1] || "").length > 0)
+ .find(
+ (header) => (header[0] || "").trim() === contentLengthHeaderName,
+ );
+ const contentLength = (contentLengthHeader || [])[1];
+ if (contentLength === undefined) {
+ await handleStreamEnded(
+ `Missing or incorrect ${contentLengthHeaderName} header: ${headers}`,
+ );
+ continue main_loop;
+ }
+ headersLength = headers.length + headerSeparator.length * 2;
+ messageLength = parseInt(contentLength, 10);
+ }
+
+ while (buffer.length < headersLength + messageLength) {
+ if (streamEnded) {
+ await handleStreamEnded(
+ `Unexpected end of stream: buffer length ${buffer.length} does not match expected header length ${headersLength} + body length ${messageLength}`,
+ );
+ continue main_loop;
+ }
+ await once(process.stdin, "readable");
+ }
+
+ const messageEnd = headersLength + messageLength;
+ const message = buffer.subarray(headersLength, messageEnd);
+ buffer = buffer.subarray(messageEnd);
+ headersLength = null;
+ messageLength = null;
+ yield message.toString("utf8");
}
+ } catch (e) {
+ sendResponse(makeError(`Error reading stdin: ${e}`));
+ } finally {
+ process.stdin.off("data", () => {});
+ }
}
async function handleMessage(message, prettier) {
- const { method, id, params } = message;
- if (method === undefined) {
- throw new Error(`Message method is undefined: ${JSON.stringify(message)}`);
- } else if (method == "initialized") {
- return;
+ const { method, id, params } = message;
+ if (method === undefined) {
+ throw new Error(`Message method is undefined: ${JSON.stringify(message)}`);
+ } else if (method == "initialized") {
+ return;
+ }
+
+ if (id === undefined) {
+ throw new Error(`Message id is undefined: ${JSON.stringify(message)}`);
+ }
+
+ if (method === "prettier/format") {
+ if (params === undefined || params.text === undefined) {
+ throw new Error(
+ `Message params.text is undefined: ${JSON.stringify(message)}`,
+ );
+ }
+ if (params.options === undefined) {
+ throw new Error(
+ `Message params.options is undefined: ${JSON.stringify(message)}`,
+ );
}
- if (id === undefined) {
- throw new Error(`Message id is undefined: ${JSON.stringify(message)}`);
+ let resolvedConfig = {};
+ if (params.options.filepath !== undefined) {
+ resolvedConfig =
+ (await prettier.prettier.resolveConfig(params.options.filepath)) || {};
}
- if (method === "prettier/format") {
- if (params === undefined || params.text === undefined) {
- throw new Error(`Message params.text is undefined: ${JSON.stringify(message)}`);
- }
- if (params.options === undefined) {
- throw new Error(`Message params.options is undefined: ${JSON.stringify(message)}`);
- }
+ const plugins =
+ Array.isArray(resolvedConfig?.plugins) &&
+ resolvedConfig.plugins.length > 0
+ ? resolvedConfig.plugins
+ : params.options.plugins;
- let resolvedConfig = {};
- if (params.options.filepath !== undefined) {
- resolvedConfig = (await prettier.prettier.resolveConfig(params.options.filepath)) || {};
- }
-
- const plugins = Array.isArray(resolvedConfig?.plugins) && resolvedConfig.plugins.length > 0 ?
- resolvedConfig.plugins :
- params.options.plugins;
-
- const options = {
- ...(params.options.prettierOptions || prettier.config),
- ...resolvedConfig,
- plugins,
- parser: params.options.parser,
- path: params.options.filepath,
- };
- process.stderr.write(
- `Resolved config: ${JSON.stringify(resolvedConfig)}, will format file '${
- params.options.filepath || ""
- }' with options: ${JSON.stringify(options)}\n`,
- );
- const formattedText = await prettier.prettier.format(params.text, options);
- sendResponse({ id, result: { text: formattedText } });
- } else if (method === "prettier/clear_cache") {
- prettier.prettier.clearConfigCache();
- prettier.config = (await prettier.prettier.resolveConfig(prettier.path)) || {};
- sendResponse({ id, result: null });
- } else if (method === "initialize") {
- sendResponse({
- id,
- result: {
- capabilities: {},
- },
- });
- } else {
- throw new Error(`Unknown method: ${method}`);
- }
+ const options = {
+ ...(params.options.prettierOptions || prettier.config),
+ ...resolvedConfig,
+ plugins,
+ parser: params.options.parser,
+ path: params.options.filepath,
+ };
+ process.stderr.write(
+ `Resolved config: ${JSON.stringify(resolvedConfig)}, will format file '${
+ params.options.filepath || ""
+ }' with options: ${JSON.stringify(options)}\n`,
+ );
+ const formattedText = await prettier.prettier.format(params.text, options);
+ sendResponse({ id, result: { text: formattedText } });
+ } else if (method === "prettier/clear_cache") {
+ prettier.prettier.clearConfigCache();
+ prettier.config =
+ (await prettier.prettier.resolveConfig(prettier.path)) || {};
+ sendResponse({ id, result: null });
+ } else if (method === "initialize") {
+ sendResponse({
+ id,
+ result: {
+ capabilities: {},
+ },
+ });
+ } else {
+ throw new Error(`Unknown method: ${method}`);
+ }
}
function makeError(message) {
- return {
- error: {
- code: -32600, // invalid request code
- message,
- },
- };
+ return {
+ error: {
+ code: -32600, // invalid request code
+ message,
+ },
+ };
}
function sendResponse(response) {
- const responsePayloadString = JSON.stringify({
- jsonrpc: "2.0",
- ...response,
- });
- const headers = `${contentLengthHeaderName}: ${Buffer.byteLength(
- responsePayloadString,
- )}${headerSeparator}${headerSeparator}`;
- process.stdout.write(headers + responsePayloadString);
+ const responsePayloadString = JSON.stringify({
+ jsonrpc: "2.0",
+ ...response,
+ });
+ const headers = `${contentLengthHeaderName}: ${Buffer.byteLength(
+ responsePayloadString,
+ )}${headerSeparator}${headerSeparator}`;
+ process.stdout.write(headers + responsePayloadString);
}
function loadPrettier(prettierPath) {
- return new Promise((resolve, reject) => {
- fs.access(prettierPath, fs.constants.F_OK, (err) => {
- if (err) {
- reject(`Path '${prettierPath}' does not exist.Error: ${err}`);
- } else {
- try {
- resolve(require(prettierPath));
- } catch (err) {
- reject(`Error requiring prettier module from path '${prettierPath}'.Error: ${err}`);
- }
- }
- });
+ return new Promise((resolve, reject) => {
+ fs.access(prettierPath, fs.constants.F_OK, (err) => {
+ if (err) {
+ reject(`Path '${prettierPath}' does not exist.Error: ${err}`);
+ } else {
+ try {
+ resolve(require(prettierPath));
+ } catch (err) {
+ reject(
+ `Error requiring prettier module from path '${prettierPath}'.Error: ${err}`,
+ );
+ }
+ }
});
+ });
}