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

Prevent incorrect indentation for Ruby's in and when keywords #198349

Conversation

vinistock
Copy link
Contributor

Currently, the language configuration decreases indentation immediately after the words in or when are typed. However, that produces some incorrect decreases.

For example, if you are including a module, the include keyword gets incorrectly dedented back.

class Foo
  include Bar # <<< indentation here is decreased incorrectly, since it's not an `in` keyword
end

The when keyword has similar issues, since you can create methods named when_something_happens and then invoking the method gets dedented incorrectly.

If we change the regex to wait for one blank space after both in and when keywords, then the indentation decrease works properly - since the blank spaces after both of them is required to specify the branch condition.

@jscheel
Copy link

jscheel commented Jan 25, 2024

This happens with end as well. While end makes sense to decrement indention, it isn't always the keyword. IIRC, this indention happened later in the past, because I used to be able to type variable names like enduser without the decremented indention auto-triggering.

@vinistock vinistock force-pushed the vs/prevent_incorrect_indentation_decrease_on_ruby branch from cb05c42 to 413e38e Compare January 30, 2024 16:55
@vinistock vinistock force-pushed the vs/prevent_incorrect_indentation_decrease_on_ruby branch from 413e38e to bd0c11e Compare January 30, 2024 16:56
@vinistock
Copy link
Contributor Author

@jscheel Yeah, we should fix that as well, although I'll split it in a separate PR.

For the end tokens, I think it would make sense to only dedent after a line break, since it's not usual to add a space after the end.

@vinistock
Copy link
Contributor Author

@rebornix any concerns with this PR?

@rebornix
Copy link
Member

@vinistock thanks for your contribution. It looks great to me, I'd like to test this thoroughly (maybe we could add some tests for it) before merging the PR. Really appreciate your help.

@rebornix rebornix added this to the February 2024 milestone Jan 30, 2024
@vinistock
Copy link
Contributor Author

I'm happy to add tests for it. Is there an example test for these language configuration files that I can base it on?

@rebornix
Copy link
Member

@vinistock it would be great if we can have tests like

test('issue #167299: Blank line removes indent', () => {
const languageId = 'blankLineRemovesIndent';
const model = createTextModel("", languageId, {});
disposables.add(model);
withTestCodeEditor(model, { autoIndent: 'full' }, (editor, viewModel, instantiationService) => {
const languageService = instantiationService.get(ILanguageService);
const languageConfigurationService = instantiationService.get(ILanguageConfigurationService);
disposables.add(languageService.registerLanguage({ id: languageId }));
disposables.add(languageConfigurationService.register(languageId, {
brackets: [
['{', '}'],
['[', ']'],
['(', ')']
],
indentationRules: javascriptIndentationRules,
onEnterRules: javascriptOnEnterRules
}));
but I can push to your branch to add some tests if you prefer, either works for me.

@vinistock
Copy link
Contributor Author

@rebornix I put together a test, but I'm having trouble with my local setup. I can't seem to yarn install successfully and thus can't run tests to verify they actually work.

If you don't mind, I'd appreciate you pushing the tests to this branch. This is what I had:

      // Other tests
      // ...

      suite('Editor Contrib - Auto Dedent On Type', () => {
	let disposables: DisposableStore;

	setup(() => {
		disposables = new DisposableStore();
	});

	teardown(() => {
		disposables.dispose();
	});

	ensureNoDisposablesAreLeakedInTestSuite();

	test('issue #198350: in or when incorrectly match non keywords for Ruby', () => {
		const languageId = "ruby";
		const model = createTextModel("", languageId, {});
		disposables.add(model);

		withTestCodeEditor(model, { autoIndent: "full" }, (editor, viewModel, instantiationService) => {
			const languageService = instantiationService.get(ILanguageService);
			const languageConfigurationService = instantiationService.get(ILanguageConfigurationService);
			disposables.add(languageService.registerLanguage({ id: languageId }));
			disposables.add(languageConfigurationService.register(languageId, {
				brackets: [
					['{', '}'],
					['[', ']'],
					['(', ')']
				],
				indentationRules: rubyIndentationRules,
			}));


			viewModel.type("def foo\n  in");
			assert.strictEqual(model.getValue(), "def foo\n  in");
		});
	});

@rebornix rebornix self-requested a review February 16, 2024 18:11
@rebornix
Copy link
Member

@vinistock it seems there are issues with the branch that our CI failed to run properly. I cherry picked your commit and packed in another PR #205397. Let's track it over there. Thanks again for your contribution!

@rebornix rebornix closed this Feb 16, 2024
@rebornix
Copy link
Member

@vinistock your change is merged via #205397 and should be available in next Insiders, cheers!

@vinistock vinistock deleted the vs/prevent_incorrect_indentation_decrease_on_ruby branch February 16, 2024 20:48
@vinistock
Copy link
Contributor Author

Thank you @rebornix!

@jscheel
Copy link

jscheel commented Feb 19, 2024

@vinistock @rebornix I'm still thinking about end causing unexpected dedents as well, and what can be done about that. It seems that the core problem is that this is relying on a pure regex to determine if auto indent/dedent should occur. However, this can only be an approximation, as we need to know what the next character entered is. Simply looking for a word boundary means that typing something as basic as enduser will immediately trigger a dedent. The determination cannot actually be made until the user types the next character. If it is a space or a carriage return, then yes, dedent should happen. But just checking on \b will cause it to trigger regardless, unless you are typing on the last line.

@vinistock
Copy link
Contributor Author

Yeah, I agree we should fix it. I believe matching on line breaks would make the most sense, since that's when you want to have it dedented.

I made an attempt, but it doesn't seem to be working. I suspect it's something with the line break regex. @rebornix do you see anything obvious that might be wrong in the new regex? Does VS Code accept \r?\n as a line break matcher?

@rebornix
Copy link
Member

@vinistock the regular expression was validated against the line content, which excludes the line breaks, thus it won't match. That's what we have for the whole regex based system, it would be a huge change if we change that. Regex system is never perfect and I personally believe a "range" formatter is always a better fit.

@vinistock
Copy link
Contributor Author

Thanks for the context. If we can't match on line breaks, then I don't think it's possible to fix this without on type formatting indeed. We need to add something to the Ruby LSP to correct format the expression after VS Code's regular dedent.

@microsoft microsoft locked and limited conversation to collaborators Jun 11, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants