Sublime Forum

Toggle single/multi line: from E-text to Sublime

#1

Hi guys. I’m migrating from E and I’m missing some features. One of that is toggling single/multi line for css properties.

Let’s say this code:

.test { color:#000; text-decoration:none; background:red; }

After I press a key combination will become

.test {color:#000; text-decoration:none; background:red; }

I know about ctrl+j command, but that will work only one way. Ok, so the code from E is this:

#!/usr/bin/env ruby

if ENV'TM_SOFT_TABS'] == 'NO'
  tab = "\t"
else
  tab = " " * ENV'TM_TAB_SIZE'].to_i
end

print case str = STDIN.read
  
  # Expand
  when /\A\{(.*)\}\z/
    "{\n#{tab}" + $1.strip.gsub("; ", ";\n#{tab}") + "\n}"
  
    # Collapse
  when /\A\{(.*)\}\z/m
    ("{" + $1.gsub("\n", " ") + "}").gsub(/\s{2,}/, " ")
  
  # Default case
  else str
    
end

My ruby and py skills are zero, so I don’t even know where to start. However, i did this:

import sublime, sublime_plugin, re

class ToggleSingleLineCommand(sublime_plugin.TextCommand):
	def run(self, edit):

Which is… all I know how to do it :smiley:

Can i get some hints/help/solution?

Thanks!

0 Likes

#2

For me, ctrl+j did exactly what you asked for (for the example you gave). What do you mean by “but that will work only one way”?

0 Likes

#3

I mean i would like to split single line rules into multiple lines rules :smiley:

From :

    .test {color:#000; text-decoration:none; background:red; }

to:

.test { color:#000; text-decoration:none; background:red; }

0 Likes

#4

Hi iamntz,

This seems to work for me (although it is definitely not well tested). It works with multiple selections and each selection should be a single css statement. It only works with css and might not work in all cases.

Happy styling :smile:

Cheers,
Josh

import sublime, sublime_plugin, re

# toggle a single-line or multi-line formatted css statement
class ToggleSingleLineCssCommand(sublime_plugin.TextCommand):
   def run(self,edit):
      for region in reversed(self.view.sel()):
            text = self.view.substr(region)

            # check if the css statement needs to be expanded or collapsed
            if re.match('^.*\{.*}\s*$', text):
                # expand the css statement
                m = re.search('^(?P<key>.*)\{(?P<params>.*)\;\s*}$', text)
                multiline = '%s{\n\t%s;\n}' % (m.group('key'), m.group('params').strip().replace('; ', ';\n\t'))
                self.view.replace(edit, region, multiline)
            else:
                # collapse the css statement
                singleline = ' '.join([x.strip() for x in text.split('\n')])
                self.view.replace(edit, region, singleline)

…and make a shortcut with something like:

{ "keys": "ctrl+shift+j"], "command": "toggle_single_line_css" }
0 Likes

#5

Awesome! Thanks a lot!

I don’t really care to work with other languages :smiley:

(it took a little to me to got it that is working only if the text is selected, but works GREAT)

0 Likes

#6

I’m lost here. :smile:
Where to put that function? - Will I have to create a new module or is there a way to put common functions in a single script file somewhere?

0 Likes

#7

Thanks for that, Josh! It’s a great start if nothing else. I’ve put off setting something like this up for ages, could have saved me thousands of manual keystrokes.

[quote=“tux.”]I’m lost here. :smile:
Where to put that function? - Will I have to create a new module or is there a way to put common functions in a single script file somewhere?[/quote]

See: sublimetext.info/docs/en/extensi … rst-plugin

0 Likes

#8

Ah, well; thanks!

0 Likes

#9

Hmm, I put the keymap into a new .sublime-keymap file there, created a new helper_functions.py, put the function in, restarted Sublime; and it doesn’t do anything?

0 Likes

#10

How are you calling it? Maybe try selecting a block of css code that you want to expand/collapse, open the console (view \ show console) and type:

view.run_command("toggle_single_line_css")

Anything?

If that doesn’t work, try adding some print statements at the beginning of the run method so you get some visual feedback (in the console) that the command is actually being called.

One important note is that the plugin requires you to select the css you want formatted, and the selection should be a single css statement. You can have multiple selections, but each selection must be an individual css statement. I’m sure the code could be improved to work on multiple css statements in a single selection but I don’t actually work with css and couldn’t be bothered to spend more time on the plugin (it was simply a fun challenge for me to solve the original poster’s problem).

I hope you are able to get it working.

0 Likes

#11

…just found some good advice from sublimator on how to debug plugins:

[quote=“sublimator”]Open a new window (File -> New Window ( ctrl+shift+n))
Resize it to take up some space in the top right hand corner of your screen
Use your window manager to make it always on top
Open the python console ( ctrl+`)

sublime.log_commands(True)

It should now output the command name and any paramaters whenever you run a command via mouse || keybinding[/quote]

0 Likes

#12

I see …

[quote]Traceback (most recent call last):
File “.\sublime_plugin.py”, line 255, in run_
File “.\helper_functions.py”, line 10, in run
NameError: global name ‘re’ is not defined[/quote]

0 Likes

#13

…oops, looks like there are some imports missing at the top. Add this line to the top of your plugin file:

import sublime, sublime_plugin, re
0 Likes

#14

Great. The error is gone.
Now the C-S-J command still doesn’t do anything…

0 Likes

#15

Ok. Try using this version with some logging included. It should print out some messages in the console that will hopefully help to understand what is going wrong. If you don’t see anything being printed into the console then I guess the shortcut isn’t set up properly.

import sublime, sublime_plugin, re

DEBUG_ENABLED = True
PRINT_CONTEXT = True

# toggle a single-line or multi-line formatted css statement
# { "keys": "ctrl+shift+j"], "command": "toggle_single_line_css" }
class ToggleSingleLineCssCommand(sublime_plugin.TextCommand):
    def run(self,edit):
        debug('Invoked "toggle_single_line_css" with %d region(s)' % (len(self.view.sel())))
        for region in reversed(self.view.sel()):
            text = self.view.substr(region)

            # check if the css statement needs to be expanded or collapsed
            if re.match('^.*\{.*}\s*$', text):
                 # expand the css statement
                 debug('The css statement needs to be expanded', text)
                 m = re.search('^(?P<key>.*)\{(?P<params>.*)\;\s*}$', text)
                 multiline = '%s{\n\t%s;\n}' % (m.group('key'), m.group('params').strip().replace('; ', ';\n\t'))
                 self.view.replace(edit, region, multiline)
            else:
                 debug('The css statement needs to be collapsed', text)
                 # collapse the css statement
                 singleline = ' '.join([x.strip() for x in text.split('\n')])
                 self.view.replace(edit, region, singleline)


def debug(text, context=""):
    if DEBUG_ENABLED:
        print '[toggle_single_line_css]: ' + text
    if PRINT_CONTEXT and context != "":
        print '>>> ' + context
0 Likes

#16

Well:

[quote][toggle_single_line_css]: Invoked “toggle_single_line_css” with 1 region(s)
[toggle_single_line_css]: The css statement needs to be collapsed[/quote]

But it doesn’t collapse.

0 Likes

#17

Is it possible for you to send me your css code?

Are you sure you have the whole css statement selected?

0 Likes

#18

I actually was!

Anyway, reloading already helped. Whew. Sorry for confusing you - works!

0 Likes

#19

Hey jbjornson, i am using your code it’s very helpful thanks, but i am facing a bug. When i have for example a css code like this:
footer{ background-color: #333; /*color: #DDD;*/ }
When the css has a comment in the bottom it won’t expand, when you remove the comment it works. I tried to fix it but i couldn’t because i never uses python.
If you can fix it i would be very thankful. Thanks.

0 Likes