Sublime Forum

Long-tag.sublime-snippet formatting issue

#1

Hi
When I try to use the long-tag I am getting a formatting issue. I have included screenshots to show.


I would love to be able to add divs around my selected text easily without it shoving my div over like 6 spaces. Am I doing something wrong?

1 Like

#2

I don’t think you’re doing anything wrong, it seems to be a bug with the indentation behavior which somehow gets triggered by this snippet

0 Likes

#3

Is there a way to fix this? I would die to use this function.

0 Likes

#4

With the simple reproduction steps, tested on build 4083:

  • New tab
  • Set syntax: HTML
  • type html Tab
  • Esc to exit snippet field mode
  • Enter to get <title>\n\t\n</title>
  • type Some Title Here
  • Edit -> Tag -> Expand Selection to Tag (so that Some Title Here is selected)
  • Edit -> Tag -> Expand Selection to Tag (so that <title>\n\tSome Title Here\n</title> is selected)
  • Edit -> Tag -> Wrap Selection with Tag
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <p><title>
            Some title here
        </title></p>
</head>
<body>

</body>
</html>

we can see that the tag is wrapped on the same line, which looks like it causes the decreaseIndentPattern rule for </title> to not apply, so it gets indented one level.
But, that pattern has no end anchor, so it should work, and indeed, selecting all text and using the reindent command gives an output that it isn’t indented more than the open tag. So I think to work around it for now, you’d want to use a plugin instead of a snippet.

I’ll see if I can draw one up in a minute.

0 Likes

#5

Thank you so much!

0 Likes

#6

you could try this - it will just issue a reindent command to the lines that were in the selection when the long-tag snippet is inserted (without affecting the snippet fields, so you can still type a new tag name):
(I originally experimented with turning off auto_indent and smart_indent temporarily, but it had no effect on the bug)
To use it, go to the Tools menu -> Developer -> New Plugin and replace the buffer with this one, and save it as something like long_tag_snippet_fixer.py (in the folder ST suggests - Packages/User) - only extension is important

import sublime
import sublime_plugin


class InsertLongTagSnippetWatcher(sublime_plugin.EventListener):
    def on_text_command(self, view, command, args):
        if command == 'insert_snippet':
            if args.get('name', None) == 'Packages/XML/Snippets/xml-long-tag.sublime-snippet':
                #self.prev_auto_indent = view.settings().get('auto_indent', None)
                #view.settings().set('auto_indent', False)
                self.sel_pos = [region for region in view.sel()]

    def on_post_text_command(self, view, command, args):
        if command == 'insert_snippet':
            if args.get('name', None) == 'Packages/XML/Snippets/xml-long-tag.sublime-snippet':
                #view.settings().set('auto_indent', self.prev_auto_indent)
                correct_sel = [region for region in view.sel()]
                view.sel().clear()
                view.sel().add_all(self.sel_pos)
                view.run_command('reindent')
                view.sel().clear()
                view.sel().add_all(correct_sel)
                
0 Likes

#7

Thanks so much for taking the time to create this. I did what you said and created the long_tag_snippet_fixer.py in the packages/User.
long_tag_snippet_fixer.py file:

import sublime
import sublime_plugin

class InsertLongTagSnippetWatcher(sublime_plugin.EventListener):
    def on_text_command(self, view, command, args):
        if command == 'insert_snippet':
            if args.get('name', None) == 'Packages/XML/Snippets/xml-long-tag.sublime-snippet':
                #self.prev_auto_indent = view.settings().get('auto_indent', None)
                #view.settings().set('auto_indent', False)
                self.sel_pos = [region for region in view.sel()]

    def on_post_text_command(self, view, command, args):
        if command == 'insert_snippet':
            if args.get('name', None) == 'Packages/XML/Snippets/xml-long-tag.sublime-snippet':
                #view.settings().set('auto_indent', self.prev_auto_indent)
                correct_sel = [region for region in view.sel()]
                view.sel().clear()
                view.sel().add_all(self.sel_pos)
                view.run_command('reindent')
                view.sel().clear()
                view.sel().add_all(correct_sel)

Then I restarted sublime. I am still getting the indentation issue though. Do I need to change something somewhere else?

0 Likes

#8

Which ST build are you using? It may be that your XML package doesn’t have a separate snippets folder

0 Likes

#9

I am using V 3.2.2 build 3211

0 Likes

#10

It looks like the Snippets folder exists, but the snippet is just called long-tag.sublime-snippet, which probably I should have guessed from your forum post title, sorry.

import sublime
import sublime_plugin
from os import path

def is_long_tag_snippet(args):
    name = args.get('name', None)
    if not name:
        return
    folder = path.dirname(name)
    file_name = path.basename(name)
    return folder == 'Packages/XML/Snippets' and file_name.endswith('long-tag.sublime-snippet')

class InsertLongTagSnippetWatcher(sublime_plugin.EventListener):
    def on_text_command(self, view, command, args):
        if command == 'insert_snippet':
            if is_long_tag_snippet(args):
                #self.prev_auto_indent = view.settings().get('auto_indent', None)
                #view.settings().set('auto_indent', False)
                self.sel_pos = [region for region in view.sel()]

    def on_post_text_command(self, view, command, args):
        if command == 'insert_snippet':
            if is_long_tag_snippet(args):
                #view.settings().set('auto_indent', self.prev_auto_indent)
                correct_sel = [region for region in view.sel()]
                view.sel().clear()
                view.sel().add_all(self.sel_pos)
                view.run_command('reindent')
                view.sel().clear()
                view.sel().add_all(correct_sel)
0 Likes

#11

Hi kingKeith,
Thank you so much for all you are doing to help! That removed the indent. This may be asking you to go above and beyond but I figured I would ask anyways. What happens now when I add the snippet is if I have this as my original code

<div>
    <p>Text Here</p>
</div>

When I add the new snippet it does

<p><div>
    <p>Add New Event</p>
</div></p>

This is good that it no longer shoves over the text but what would be ideal in my perfect world would be

<p>
   <div>
       <p>Add New Event</p>
   </div>
</p>

I don’t suppose that is a easy change?

0 Likes

#12

if you’ve got the OverrideAudit plugin installed, you can:

  • Open the Command Palette
  • type OA:
  • select OverrideAudit: Create Override
  • choose XML, then Snippets then xml- long-tag.sublime-snippet
  • replace the contents with the following
<snippet>
	<content><![CDATA[<${1:p}>
	${0:$SELECTION}
</${1/([^ ]+).*/$1/}>]]></content>
	<tabTrigger>lt</tabTrigger>
	<scope>text.xml - meta.tag - comment - string</scope>
	<description>Long Tag</description>
</snippet>
  • save it
0 Likes

#13

That worked and Its almost there!!!
If I just have

<p>Test words</p>

when I do the snippet I get

<p>
    <p>Test words</p>
</p>

Wooooo! The only catch now is if I try to do something like

<p>
    <p>Test words</p>
</p>

I get

<p>
   <p>
              <p>Test words</p>
          </p>
</p>
0 Likes

#14

I haven’t been able to replicate that behaviour yet… Does it make a difference if you reindent the whole file first?

1 Like

#15

I did some testing on my end and it is definitely an issue with different files. I must have some weird indentation issues. When I use a clean file it works great.
Thank you sooo much for all of your help with this, you have been amazing!

0 Likes

#16

okay, for a plugin solution instead of a snippet - such that this bug isn’t triggered, and it doesn’t affect indentation at all:

import sublime
import sublime_plugin
from os import path

def is_long_tag_snippet(args):
    name = args.get('name', None)
    if not name:
        return
    folder = path.dirname(name)
    file_name = path.basename(name)
    return folder == 'Packages/XML/Snippets' and file_name.endswith('long-tag.sublime-snippet')

class InsertLongTagSnippetWatcher(sublime_plugin.EventListener):
    def on_text_command(self, view, command, args):
        if command == 'insert_snippet':
            if is_long_tag_snippet(args):
                return ('insert_xml_tag', { 'tag': 'p' })

class InsertXmlTagCommand(sublime_plugin.TextCommand):
    def run(self, edit, **args):
        tag = args.get('tag', 'p')
        for sel in reversed(self.view.sel()):
            self.view.insert(edit, sel.end(), '</' + tag + '>')
            self.view.insert(edit, sel.begin(), '<' + tag + '>')
            #self.view.sel().add(sublime.Region(sel.begin(), sel.end() + ((len(tag) + 2) * 2) + 1))
            self.view.sel().add(sublime.Region(sel.begin() + 1, sel.begin() + 1 + len(tag)))
            self.view.sel().add(sublime.Region(sel.end() + len('<' + tag + '></'), sel.end() + len('<' + tag + '></') + len(tag)))
            self.view.sel().subtract(sublime.Region(sel.begin() + len('<' + tag + '>'), sel.end() + len('<' + tag + '>')))

however, it currently loses the ability to press Tab to go to the contents of the tag (i.e. the selection that got wrapped).
EDIT: and I just realised it also doesn’t cater for putting the wrapped selection on a new line and indenting it…

1 Like

#17

I just saw this now. Thank you so much!!

0 Likes