emmetio / sublime-text-plugin

The essential toolkit for web-developers
https://emmet.io
MIT License
253 stars 29 forks source link

JSX Element as props will replace tag after jsx Element prop has expanded. #185

Closed iahu closed 1 month ago

iahu commented 9 months ago

Firstly, thanks your great work.

I hit a issue everyday, which for example, I have some jsx code, looks like below:

<Card title={<Button|}></Card>

my cursor is placed after <Button|, and I press Tab to expand the <Button tag, the result will be:

<Button></Card>

but not

<Card title={<Button><Button>}></Card>

as expected.

Hope this can be solved, thank you.

sergeche commented 9 months ago

Writing tags inside attributes is a bit awkward and invalid in HTML (Emmet was developed for HTML), yet in JSX it’s perfectly valid. Will try to figure out how to make it work in Sublime Text

vizvamitra commented 2 months ago

Hi. Let me add to this instead of creating a separate issue cause it seems related. Looks like pressing Tab while cursor is anywhere on the line that starts with < produces weird behavior.

https://github.com/user-attachments/assets/4bcc1ef9-5b2a-4595-8da0-e217575da234

Regarding the example above, even render <Card title="test"></Card>; is being replaced with return <test></test>"></Card>; is the cursor is before the closing quote. I've also noticed this weird replacement:

https://github.com/user-attachments/assets/e5f1184e-38f3-434f-8d53-0bb8077aeac7

Though this might help in debugging

vizvamitra commented 2 months ago

As a temporary solution that both gets rid of the bug and keeps emmet usable with jsx, I've used OverrideAudit plugin to change my local copy of emmet plugin, overriding jsx prefix here with ±. (rare in code, easy to type on mac).

sergeche commented 2 months ago

@vizvamitra it seems like a bug in abbreviation detection logic that detects if you’re typing abbreviation or just a regular word. In your first video, detected abbreviation is <div class="flex (yellow underline) which is invalid since it should reset abbreviation after space. Looks like you’re using some plugins or completions with that. Can you create a full video how you typed that div and received broken abbreviation?

vizvamitra commented 2 months ago

Sure. First video shows behavior with all my completions plugins (LSP-copilot, LSP-tailwindcss) enabled, on the second one I've disabled those two but the bug persisted

https://github.com/user-attachments/assets/a8d35ae0-4958-43d4-9a3f-ca3c18160068

https://github.com/user-attachments/assets/a68cfb08-14b0-4781-9216-42b729aff9c7

vizvamitra commented 2 months ago

Some insights here.

I guess one thing that goes wrong is that py-emmet's extract, when called here with a prefix, recognizes as abbreviation the whole line starting with that prefix instead of just the last word:

from emmet import extract

extract('      <div.foo test', 19, {
  'type': 'markup',
  'lookAhead': True,
  'prefix': '<'
})

# => {'abbreviation': 'test', 'location': 15, 'start': 6, 'end': 19}

extract('      div.foo test', 19, {
  'type': 'markup',
  'lookAhead': True,
  'prefix': ''
})

# => {'abbreviation': 'test', 'location': 14, 'start': 14, 'end': 18}

I guess this is being called when user presses Tab while no active tracker, and the fact that resulting start..end range starts from <div causes plugin to replace the whole line.

But I guess this is not what happens on my video, cause there seem to be an existing tracker at that moment (according to the logging I've put into the code while debugging)

sergeche commented 2 months ago

Thanks, that helps a lot!

sergeche commented 1 month ago

Both issues should be fixed in v.2.4.4