Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking β€œSign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(vscode): make quick-lint a jerk πŸ–• #1190

Closed
wants to merge 2 commits into from
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
feat(vscode): make quick-lint a jerk πŸ–•
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
commit c7f6f597283df0d3b21c843cab5f09a6114d1be9
6 changes: 6 additions & 0 deletions plugin/vscode/package.json
Original file line number Diff line number Diff line change
@@ -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."
}
}
},
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
@@ -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) {
@@ -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) {
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
@@ -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(); }

@@ -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&,
@@ -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);
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
@@ -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)});
@@ -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(); });
}
@@ -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 {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Compiler was warning about is_snarky being an unused capture. I fixed it by using [&] instead.

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();
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
@@ -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);
@@ -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_;
109 changes: 108 additions & 1 deletion plugin/vscode/test/vscode-tests.js
Original file line number Diff line number Diff line change
@@ -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,

@@ -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);
1 change: 1 addition & 0 deletions src/quick-lint-js/i18n/translation.cpp
Original file line number Diff line number Diff line change
@@ -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);
Loading