Skip to content

Commit

Permalink
feat(vscode): make quick-lint a jerk πŸ–•
Browse files Browse the repository at this point in the history
Summary: It ticks me off 😠 how polite πŸ˜‡ quick-lint is when I code.  If I mess
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 sissy 😭
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 21, 2024
1 parent 55362b8 commit c7f6f59
Show file tree
Hide file tree
Showing 7 changed files with 172 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
12 changes: 12 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,12 @@ void QLJS_Config_Document::on_config_file_changed(
diagnostic_collection);
}

void QLJS_Config_Document::on_translator_changed(
::Napi::Env env, QLJS_Workspace& workspace,
VSCode_Diagnostic_Collection diagnostic_collection) {
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 +112,12 @@ void QLJS_Lintable_Document::on_config_file_changed(
diagnostic_collection);
}

void QLJS_Lintable_Document::on_translator_changed(
::Napi::Env env, QLJS_Workspace& workspace,
VSCode_Diagnostic_Collection diagnostic_collection) {
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
9 changes: 9 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,6 +94,10 @@ class QLJS_Document_Base {
VSCode_Diagnostic_Collection,
Loaded_Config_File* config_file) = 0;

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

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

Expand All @@ -118,6 +122,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 on_translator_changed(
::Napi::Env env, QLJS_Workspace& workspace,
VSCode_Diagnostic_Collection diagnostic_collection) override;

private:
void lint_config_and_publish_diagnostics(::Napi::Env, QLJS_Workspace&,
Expand All @@ -142,6 +149,8 @@ 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 on_translator_changed(::Napi::Env, QLJS_Workspace&,
VSCode_Diagnostic_Collection) override;

void lint_javascript_and_publish_diagnostics(::Napi::Env, QLJS_Workspace&,
VSCode_Diagnostic_Collection);
Expand Down
30 changes: 29 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,29 @@ ::Napi::Value QLJS_Workspace::configuration_changed(
::Napi::Env env = info.Env();

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

return env.Undefined();
}

void QLJS_Workspace::on_translator_changed(::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->on_translator_changed(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 on_translator_changed(::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
109 changes: 108 additions & 1 deletion plugin/vscode/test/vscode-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,113 @@ for (let extension of [".js", ".mjs", ".cjs", ".jsx"]) {
};
}

// SNARKY tests
for (let testCase of [
{
fileName: "hello.js",
content: "undeclaredVariable",
englishMessage: "use of undeclared variable: undeclaredVariable",
snarkyEnglishMessage: "did you fail spelling class?",
},
{
fileName: "quick-lint-js.config",
content: "{",
englishMessage: "JSON syntax error",
snarkyEnglishMessage: "yeah, JSON sucks; try quick-lint-json",
},
]) {
tests = {
...tests,
[`snarky enabled at start (${testCase.fileName})`]: async ({
addCleanup,
}) => {
addCleanup(resetConfigurationAsync);

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

let scratchDirectory = makeScratchDirectory({ addCleanup });
let filePath = path.join(scratchDirectory, testCase.fileName);
fs.writeFileSync(filePath, testCase.content);
let helloURI = vscode.Uri.file(filePath);
let helloDocument = await vscode.workspace.openTextDocument(helloURI);
await loadExtensionAsync({ addCleanup });
let helloEditor = await vscode.window.showTextDocument(helloDocument);

await waitUntilAnyDiagnosticsAsync(helloURI);
let diags = normalizeDiagnostics(helloURI).map(({ message }) => message);
assert.deepStrictEqual(diags, [testCase.snarkyEnglishMessage]);
},

[`enabling snarky re-lints (${testCase.fileName})`]: async ({
addCleanup,
}) => {
addCleanup(resetConfigurationAsync);
await loadExtensionAsync({ addCleanup });
let scratchDirectory = makeScratchDirectory({ addCleanup });
let filePath = path.join(scratchDirectory, testCase.fileName);
fs.writeFileSync(filePath, testCase.content);
let helloURI = vscode.Uri.file(filePath);
let helloDocument = await vscode.workspace.openTextDocument(helloURI);
let helloEditor = await vscode.window.showTextDocument(helloDocument);

// 1. Make sure we're polite at the start
{
await waitUntilAnyDiagnosticsAsync(helloURI);
let diagMessages = normalizeDiagnostics(helloURI).map(
({ message }) => message
);
assert.deepStrictEqual(diagMessages, [testCase.englishMessage]);
}

// 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 diagMessages = normalizeDiagnostics(helloURI).map(
({ message }) => message
);
let want = [testCase.snarkyEnglishMessage];
assert.deepStrictEqual(diagMessages, want);
});
},

[`disabling snarky re-lints (${testCase.fileName})`]: async ({
addCleanup,
}) => {
addCleanup(resetConfigurationAsync);
await vscode.workspace
.getConfiguration("quick-lint-js")
.update("snarky", true, vscode.ConfigurationTarget.Workspace);
let scratchDirectory = makeScratchDirectory({ addCleanup });
let filePath = path.join(scratchDirectory, testCase.fileName);
fs.writeFileSync(filePath, testCase.content);
let helloURI = vscode.Uri.file(filePath);
let helloDocument = await vscode.workspace.openTextDocument(helloURI);
await loadExtensionAsync({ addCleanup });
let helloEditor = await vscode.window.showTextDocument(helloDocument);

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

// 2. Make sure we're polite now
await pollAsync(() => {
let diagMessages = normalizeDiagnostics(helloURI).map(
({ message }) => message
);
let want = [testCase.englishMessage];
assert.deepStrictEqual(diagMessages, want);
});
},
};
}

tests = {
...tests,

Expand Down Expand Up @@ -1535,7 +1642,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 c7f6f59

Please sign in to comment.