Skip to content

Commit

Permalink
feat(vscode): make quick-lint an asshole πŸ–•
Browse files Browse the repository at this point in the history
Summary: It pisses me off 😠 how polite πŸ˜‡ quick-lint is when I code.  If I fuck up 😬, I want it
to tell me.  Stop beating around the bush 🌳 and tell it to me like it is. πŸ’―

Test plan: πŸ“
1. open TypeScript file with no errors in it βœ…
2. add an error ❌
3. note how quick-lint tells you what the problem is like a pussy 😭
4. enable settings > quick-lint-js > snarky 😈
5. note how quick-lint is straight up with you.  You suck. πŸ—‘οΈ

Closes #1188
  • Loading branch information
vegerot committed Jan 17, 2024
1 parent 10884a5 commit f241633
Show file tree
Hide file tree
Showing 7 changed files with 264 additions and 2 deletions.
6 changes: 6 additions & 0 deletions plugin/vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@
],
"default": "off",
"description": "Log document changes. Useful for quick-lint-js contributors."
},
"quick-lint-js.snarky": {
"scope": "window",
"type": "boolean",
"default": false,
"description": "Add spice to your failures"
}
}
},
Expand Down
14 changes: 14 additions & 0 deletions plugin/vscode/quick-lint-js/vscode/qljs-document.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ void QLJS_Config_Document::on_config_file_changed(
diagnostic_collection);
}

void QLJS_Config_Document::update_is_snarky(
bool is_snarky_enabled, ::Napi::Env env, QLJS_Workspace& workspace,
VSCode_Diagnostic_Collection diagnostic_collection) {
this->is_snarky_enabled_ = is_snarky_enabled;
this->lint_config_and_publish_diagnostics(env, workspace,
diagnostic_collection);
}
void QLJS_Config_Document::lint_config_and_publish_diagnostics(
::Napi::Env env, QLJS_Workspace& workspace,
VSCode_Diagnostic_Collection diagnostic_collection) {
Expand Down Expand Up @@ -106,6 +113,13 @@ void QLJS_Lintable_Document::on_config_file_changed(
diagnostic_collection);
}

void QLJS_Lintable_Document::update_is_snarky(
bool is_snarky_enabled, ::Napi::Env env, QLJS_Workspace& workspace,
VSCode_Diagnostic_Collection diagnostic_collection) {
this->is_snarky_enabled_ = is_snarky_enabled;
this->lint_javascript_and_publish_diagnostics(env, workspace,
diagnostic_collection);
}
void QLJS_Lintable_Document::lint_javascript_and_publish_diagnostics(
::Napi::Env env, QLJS_Workspace& workspace,
VSCode_Diagnostic_Collection diagnostic_collection) {
Expand Down
12 changes: 12 additions & 0 deletions plugin/vscode/quick-lint-js/vscode/qljs-document.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,18 @@ class QLJS_Document_Base {
VSCode_Diagnostic_Collection,
Loaded_Config_File* config_file) = 0;

virtual void update_is_snarky(
bool is_snarky_enabled, ::Napi::Env env, QLJS_Workspace& workspace,
VSCode_Diagnostic_Collection diagnostic_collection) = 0;

protected:
::Napi::Value uri() { return this->vscode_document_.Value().uri(); }

LSP_Document_Text document_;
::Napi::Reference<VSCode_Document> vscode_document_;

bool is_snarky_enabled_ = false;

friend class QLJS_Workspace;
};

Expand All @@ -118,6 +124,9 @@ class QLJS_Config_Document : public QLJS_Document_Base {
void on_config_file_changed(::Napi::Env, QLJS_Workspace&,
VSCode_Diagnostic_Collection,
Loaded_Config_File* config_file) override;
void update_is_snarky(
bool is_snarky_enabled, ::Napi::Env env, QLJS_Workspace& workspace,
VSCode_Diagnostic_Collection diagnostic_collection) override;

private:
Loaded_Config_File* loaded_config_ = nullptr;
Expand All @@ -141,6 +150,9 @@ class QLJS_Lintable_Document : public QLJS_Document_Base {
void on_config_file_changed(::Napi::Env, QLJS_Workspace&,
VSCode_Diagnostic_Collection,
Loaded_Config_File* config_file) override;
void update_is_snarky(
bool is_snarky_enabled, ::Napi::Env env, QLJS_Workspace& workspace,
VSCode_Diagnostic_Collection diagnostic_collection) override;

void lint_javascript_and_publish_diagnostics(::Napi::Env, QLJS_Workspace&,
VSCode_Diagnostic_Collection);
Expand Down
34 changes: 33 additions & 1 deletion plugin/vscode/quick-lint-js/vscode/qljs-workspace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,14 @@ class Extension_Configuration {
}
}

bool get_snarky(::Napi::Env env) {
::Napi::Value value = this->get(env, "snarky");
if (!value.IsBoolean()) {
return false;
}
return value.As<::Napi::Boolean>();
}

::Napi::Value get(::Napi::Env env, const char* section) {
return this->config_ref_.Get("get").As<::Napi::Function>().Call(
this->config_ref_.Value(), {::Napi::String::New(env, section)});
Expand Down Expand Up @@ -124,7 +132,8 @@ QLJS_Workspace::QLJS_Workspace(const Napi::CallbackInfo& info)
::Napi::Persistent(info[2].As<::Napi::Object>())),
ui_(this) {
QLJS_DEBUG_LOG("Workspace %p: created\n", this);
this->update_logging(info.Env());
configuration_changed(info);

this->fs_change_detection_thread_ =
Thread([this]() -> void { this->run_fs_change_detection_thread(); });
}
Expand Down Expand Up @@ -234,10 +243,33 @@ ::Napi::Value QLJS_Workspace::configuration_changed(
::Napi::Env env = info.Env();

this->update_logging(env);
this->update_is_snarky(env);

return env.Undefined();
}

bool QLJS_Workspace::is_snarky_enabled() const {
return this->is_snarky_enabled_;
}

void QLJS_Workspace::update_is_snarky(::Napi::Env env) {
Extension_Configuration config(env, this->vscode_);
bool is_snarky = config.get_snarky(env);

this->is_snarky_enabled_ = is_snarky;
if (is_snarky) {
this->translator_.use_messages_from_locale("en_US@snarky");
} else {
// TODO(#529): Use the locale from the VS Code configuration.
this->translator_.use_messages_from_source_code();
}
this->qljs_documents_.for_each([this, is_snarky,
env](::Napi::Value value) -> void {
QLJS_Document_Base* doc = QLJS_Document_Base::unwrap(value);
doc->update_is_snarky(is_snarky, env, *this, this->diagnostic_collection());
});
}

::Napi::Value QLJS_Workspace::editor_visibility_changed(
const Napi::CallbackInfo& info) {
::Napi::Env env = info.Env();
Expand Down
7 changes: 7 additions & 0 deletions plugin/vscode/quick-lint-js/vscode/qljs-workspace.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ class QLJS_Workspace : public ::Napi::ObjectWrap<QLJS_Workspace> {
// Disable logging if logging is enabled.
void disable_logging();

void update_is_snarky(::Napi::Env env);

~QLJS_Workspace();

::Napi::Value dispose(const ::Napi::CallbackInfo& info);
Expand Down Expand Up @@ -248,8 +250,13 @@ class QLJS_Workspace : public ::Napi::ObjectWrap<QLJS_Workspace> {
QLJS_Workspace* workspace_;
};

public:
bool is_snarky_enabled() const;

private:
bool is_snarky_enabled_ = false;
Translator translator_;

bool disposed_ = false;
VSCode_Tracer tracer_;
VSCode_Module vscode_;
Expand Down
192 changes: 191 additions & 1 deletion plugin/vscode/test/vscode-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -1095,6 +1095,196 @@ tests = {

// TODO(strager): Allow the user to delete the extenion, thereby deleting
// the output channel.

snarky_enabled_at_start: async ({ addCleanup }) => {
addCleanup(resetConfigurationAsync);

await vscode.workspace
.getConfiguration("quick-lint-js")
.update("snarky", true, vscode.ConfigurationTarget.Workspace);

let scratchDirectory = makeScratchDirectory({ addCleanup });
let helloFilePath = path.join(scratchDirectory, "hello.js");
fs.writeFileSync(helloFilePath, "let x = undeclaredVariable;\n");
let helloURI = vscode.Uri.file(helloFilePath);
let helloDocument = await vscode.workspace.openTextDocument(helloURI);
await loadExtensionAsync({ addCleanup });
let helloEditor = await vscode.window.showTextDocument(helloDocument);

await waitUntilAnyDiagnosticsAsync(helloURI);
let diags = normalizeDiagnostics(helloURI);
diags = diags.map(({ code, severity, message }) => ({
code,
severity,
message,
}));
assert.deepStrictEqual(diags, [
// use of undeclared variable 'undeclaredVariable'
{
code: {
target: "https://quick-lint-js.com/errors/E0057/",
value: "E0057",
},
severity: vscode.DiagnosticSeverity.Warning,
message: "did you fail spelling class?",
},
]);
},

enable_snarky: async ({ addCleanup }) => {
addCleanup(resetConfigurationAsync);
await loadExtensionAsync({ addCleanup });
let scratchDirectory = makeScratchDirectory({ addCleanup });
let helloFilePath = path.join(scratchDirectory, "hello.js");
fs.writeFileSync(helloFilePath, "let x = undeclaredVariable;\n");
let helloURI = vscode.Uri.file(helloFilePath);
let helloDocument = await vscode.workspace.openTextDocument(helloURI);
let helloEditor = await vscode.window.showTextDocument(helloDocument);

// 1. Make sure we're not snarky at the start
{
await waitUntilAnyDiagnosticsAsync(helloURI);
let diags = normalizeDiagnostics(helloURI);
diags = diags.map(({ code, severity, message }) => ({
code,
severity,
message,
}));
assert.deepStrictEqual(diags, [
// use of undeclared variable 'undeclaredVariable'
{
code: {
target: "https://quick-lint-js.com/errors/E0057/",
value: "E0057",
},
severity: vscode.DiagnosticSeverity.Warning,
message: "use of undeclared variable: undeclaredVariable",
},
]);
}

// 2. Enable snarky
await vscode.workspace
.getConfiguration("quick-lint-js")
.update("snarky", true, vscode.ConfigurationTarget.Workspace);

// 3. Make sure we're snarky now
await pollAsync(() => {
let diags = normalizeDiagnostics(helloURI);
diags = diags.map(({ code, severity, message }) => ({
code,
severity,
message,
}));
let got = diags;
let want = [
{
code: {
target: "https://quick-lint-js.com/errors/E0057/",
value: "E0057",
},
severity: vscode.DiagnosticSeverity.Warning,
message: "did you fail spelling class?",
},
];
assert.deepStrictEqual(diags, want);
});
},

// this starts off the exact same as snarky_enabled_at_start, so maybe these
// tests should be merged
disable_snarky: async ({ addCleanup }) => {
addCleanup(resetConfigurationAsync);

await vscode.workspace
.getConfiguration("quick-lint-js")
.update("snarky", true, vscode.ConfigurationTarget.Workspace);

let scratchDirectory = makeScratchDirectory({ addCleanup });
let helloFilePath = path.join(scratchDirectory, "hello.js");
fs.writeFileSync(helloFilePath, "let x = undeclaredVariable;\n");
let helloURI = vscode.Uri.file(helloFilePath);
let helloDocument = await vscode.workspace.openTextDocument(helloURI);
await loadExtensionAsync({ addCleanup });
let helloEditor = await vscode.window.showTextDocument(helloDocument);

// 1. Make sure we're snarky at the start
await waitUntilAnyDiagnosticsAsync(helloURI);
let diags = normalizeDiagnostics(helloURI);
diags = diags.map(({ code, severity, message }) => ({
code,
severity,
message,
}));
assert.deepStrictEqual(diags, [
// use of undeclared variable 'undeclaredVariable'
{
code: {
target: "https://quick-lint-js.com/errors/E0057/",
value: "E0057",
},
severity: vscode.DiagnosticSeverity.Warning,
message: "did you fail spelling class?",
},
]);

// 2. Disable snarky
await vscode.workspace
.getConfiguration("quick-lint-js")
.update("snarky", false, vscode.ConfigurationTarget.Workspace);

// 3. Make sure we're polite now
await pollAsync(() => {
let diags = normalizeDiagnostics(helloURI);
diags = diags.map(({ code, severity, message }) => ({
code,
severity,
message,
}));
let got = diags;
let want = [
{
code: {
target: "https://quick-lint-js.com/errors/E0057/",
value: "E0057",
},
severity: vscode.DiagnosticSeverity.Warning,
message: "use of undeclared variable: undeclaredVariable",
},
];
assert.deepStrictEqual(diags, want);
});
},
snarky_enabled_at_start_config_file: async ({ addCleanup }) => {
addCleanup(resetConfigurationAsync);
await vscode.workspace
.getConfiguration("quick-lint-js")
.update("snarky", true, vscode.ConfigurationTarget.Workspace);
let scratchDirectory = makeScratchDirectory({ addCleanup });
let configFilePath = path.join(scratchDirectory, "quick-lint-js.config");
fs.writeFileSync(configFilePath, "{");
let configURI = vscode.Uri.file(configFilePath);

await loadExtensionAsync({ addCleanup });
let configDocument = await vscode.workspace.openTextDocument(configURI);
let configEditor = await vscode.window.showTextDocument(configDocument);

await waitUntilAnyDiagnosticsAsync(configURI);

let configDiags = normalizeDiagnostics(configURI);
assert.deepStrictEqual(
configDiags.map(({ code, message }) => ({ code, message })),
[
{
code: {
target: "https://quick-lint-js.com/errors/E0164/",
value: "E0164",
},
message: "yeah, JSON sucks; try quick-lint-json",
},
]
);
},
};

if (os.platform() === "linux") {
Expand Down Expand Up @@ -1535,7 +1725,7 @@ async function pollAsync(callback) {
}

async function resetConfigurationAsync() {
for (let setting of ["logging"]) {
for (let setting of ["logging", "snarky"]) {
await vscode.workspace
.getConfiguration("quick-lint-js")
.update(setting, undefined, vscode.ConfigurationTarget.Workspace);
Expand Down
1 change: 1 addition & 0 deletions src/quick-lint-js/i18n/translation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ Span<std::string_view> get_user_locale_preferences(

// TODO(strager): Determine the language using macOS' and Windows' native
// APIs. See GNU gettext's _nl_language_preferences_default.
// TODO (#529): Also use VSCode's "Display Language" setting

Vector<std::string_view> locales("locales", allocator);
locales.push_back(locale);
Expand Down

0 comments on commit f241633

Please sign in to comment.