Skip to content

Conversation

tarkah
Copy link

@tarkah tarkah commented Aug 28, 2025

Adds a new code action to create an unknown module. This allows you to easily define new modules without having to leave your editor.

Screen.Recording.2025-08-27.at.11.19.35.PM.mov

@GearsDatapacks
Copy link
Member

Hi, thank you for this! This seems like something we want, but we generally don't accept unplanned PRs. Would you mind making an issue about this, so we can discuss how exactly we want this to work? I feel I would want this code action available for all modules, not just sub-modules of the current one, though others may have different opinions.

@tarkah tarkah marked this pull request as draft August 28, 2025 19:14
@tarkah
Copy link
Author

tarkah commented Aug 28, 2025

Absolutely! I've moved this to draft for now and created an issue here: #4894

@tarkah tarkah force-pushed the feat/create-unknown-module-code-action branch from ac76b78 to 78681dc Compare August 29, 2025 01:25
@lpil
Copy link
Member

lpil commented Aug 29, 2025

Is this ready for review?

@tarkah tarkah marked this pull request as ready for review August 29, 2025 13:52
@tarkah
Copy link
Author

tarkah commented Aug 29, 2025

Is this ready for review?

Yup! I've just moved it off draft.

Copy link
Member

@lpil lpil left a comment

Choose a reason for hiding this comment

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

Thank you! This is looking really nice. I've left a small comments inline, and the build is failing currently.

Would you mind updating the changelog file too please 🙏

/// ```gleam
/// // foo.gleam
/// // Diagnostic: Unknown module
/// import foo/bar/baz
Copy link
Member

Choose a reason for hiding this comment

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

nit: Remove foobar references please, it has a not-very-cheery WW2 association so we avoid it in favour of more lighthearted examples.

///
/// ```gleam
/// // foo/bar/baz.gleam
/// ```
Copy link
Member

Choose a reason for hiding this comment

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

These two code examples are not very clear, so let's describe this code action using words instead.

.input_path
.as_str()
.strip_suffix(&format!("{}.gleam", self.module.name))
.expect("origin is ancestor of module path");
Copy link
Member

Choose a reason for hiding this comment

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

Path manipulation can only happen in the ProjectPaths class, so pass that into the code action class from the LS engine instance and use module.origin to determine which directory to use.

This also enables us to avoid panicking, which we always try to avoid.

let uri = Url::from_file_path(format!("{origin_path}/{}.gleam", unknown_module.name))
.expect("origin path is absolute");

CodeActionBuilder::new(format!("Create module {}.gleam", unknown_module.name))
Copy link
Member

Choose a reason for hiding this comment

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

This should either be Create module wibble/wobble or Create src/wibble/wobble.gleam as module names don't have a .gleam suffix, Gleam file paths do.

});

for unknown_module in unknown_modules {
if !self.code_action_span.intersects(*unknown_module.location) {
Copy link
Member

Choose a reason for hiding this comment

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

Contains rather than intersects please. We don't want to trigger this if someone selects a larger block that happens to include this error.

@tarkah tarkah force-pushed the feat/create-unknown-module-code-action branch from 78681dc to 7fcc8f7 Compare September 3, 2025 03:45
@tarkah
Copy link
Author

tarkah commented Sep 3, 2025

Thanks for the feedback @lpil! I've addressed your comments, let me know if there is anything else that should be addressed.

@tarkah tarkah requested a review from lpil September 3, 2025 03:52
Copy link
Member

@lpil lpil left a comment

Choose a reason for hiding this comment

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

Fantastic! Thank you! Looks really good.

I missed in the last review that there are no tests, sorry about that. Could you add tests, including ones that make sure that src, test, and dev are appropriately picked for the new file.

When you are ready for a review please un-draft this PR and tag me for a review. Thank you!

@lpil lpil marked this pull request as draft September 3, 2025 11:54
@tarkah tarkah force-pushed the feat/create-unknown-module-code-action branch from 7fcc8f7 to 332f6ed Compare September 4, 2025 05:51
@tarkah tarkah marked this pull request as ready for review September 4, 2025 05:51
@tarkah tarkah requested a review from lpil September 4, 2025 05:51
@tarkah
Copy link
Author

tarkah commented Sep 4, 2025

@lpil Thanks! Tests are added. Let me know what you think of the refactoring needed to support defining an origin & module with TestProject::at in a backwards compatible way.

@tarkah tarkah force-pushed the feat/create-unknown-module-code-action branch from 332f6ed to f254f5e Compare September 4, 2025 05:55
Copy link
Member

@lpil lpil left a comment

Choose a reason for hiding this comment

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

Thank you, very nice. The tests look great, but I've left some notes inline about the changes to the test API. Once that is sorted we can merge, thanks!

Module(Origin, &'a str, Position),
}

impl From<Position> for Cursor<'_> {
Copy link
Member

Choose a reason for hiding this comment

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

Never implement traits in this codebase please.

.expect("Module doesn't exist")
};

let ((mut engine, params), code) = match cursor {
Copy link
Member

Choose a reason for hiding this comment

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

Rather than overloading this function please create a new function for positioning within a different file, if needed.


#[test]
fn create_unknown_module_under_src() {
assert_code_action_file_operations!(
Copy link
Member

Choose a reason for hiding this comment

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

Could we not teach the existing macro how to understand these file operation changes too? It has the nice output which we want to have here, and it would be good to to have to maintain twice as many macros.


let response = engine.compile_please();
assert!(response.result.is_ok());
let _response = engine.compile_please();
Copy link
Member

Choose a reason for hiding this comment

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

🔴 Compile errors no longer cause the tests to fail!

Copy link
Author

Choose a reason for hiding this comment

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

This code action requires the type error to be present, positioned_with_io allows them so I can test when invoking code actions in self.src but if we assert on compiler errors under positioned_with_io_in_src/dev/test then I can't trigger this code action within specific modules.

How do you suggest we go about that?

Copy link
Member

Choose a reason for hiding this comment

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

We have existing code actions that only trigger when code fails to compile, how are those tested?

Copy link
Author

@tarkah tarkah Sep 7, 2025

Choose a reason for hiding this comment

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

They all only use TestProject::at / positioned_with_io which doesn't make this assertion

Copy link
Author

Choose a reason for hiding this comment

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

Hey @lpil, friendly bump. How'd you like to move forward on this?

@tarkah tarkah force-pushed the feat/create-unknown-module-code-action branch from f254f5e to 4d373c3 Compare September 5, 2025 21:41
@tarkah tarkah requested a review from lpil September 5, 2025 21:45
@tarkah
Copy link
Author

tarkah commented Sep 5, 2025

@lpil Appreciate the great feedback. I've addressed your comments, though see #4888 (comment)

@tarkah tarkah force-pushed the feat/create-unknown-module-code-action branch 2 times, most recently from 4f7ca62 to 383f986 Compare September 11, 2025 21:32
@tarkah tarkah force-pushed the feat/create-unknown-module-code-action branch from 383f986 to 655236a Compare October 4, 2025 03:41
@tarkah
Copy link
Author

tarkah commented Oct 4, 2025

Hey @lpil checking in on this, can I get another review / finalize a decision on #4888 (comment)?

I've rebased and this is otherwise good to go.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants