Sublime Forum



I’m creating a plugin to get all the properties ( CSS ) within the selector and sort all of them alphabetically, then replace the sorted one with the original one. This way, I don’t have to use mouse to select all the properties and press f9 each time, and a key binding would do the job now with my plugin.

It’s working well, but the Sublime Text would clash every time when I try to run this plugin for the last selector of the CSS file. Assume we have the below CSS:

#second {
	right: 0;
	position: relative;
	left: 0;
	position: absolute;
	bottom: 0;

.test {
	position: absolute;
	bottom: 0;
	top: 0;

.second {
	right: 0;
	position: relative;
	left: 0;

You can try to put the cursor at any property, it will work. But if the active line is right: 0; or position: relative; or left: 0; from the selector .second. 100% Sublime Text will clash.

I cannot figure why as the plugin looks fine. I’m not sure if my code is wrong logically or technically or this is a bug from Sublime Text, any expert here can help?

Update: I found that it will only clash when the }of the last selector is the last line of the file

Below is the plugin code:

import sublime
import sublime_plugin

class sort_css_properties(sublime_plugin.TextCommand):
	def run(self, edit):
		view = self.view
		position = view.sel()[0].end()
		lineNumber = view.rowcol(position)[0]
		currentNumber = [0, 1]
		backwardNumber = [-1, 0]
		forwardNumber = [1, 2]
		currentLineStart = view.text_point(lineNumber + currentNumber[0], 0)
		currentLineEnd = view.text_point(lineNumber + currentNumber[1], 0)
		currentLineContent = view.substr(sublime.Region(currentLineStart, currentLineEnd))
		previousLineStart = view.text_point(lineNumber + backwardNumber[0], 0)
		previousLineEnd = view.text_point(lineNumber + backwardNumber[1], 0)
		previousLineContent = view.substr(sublime.Region(previousLineStart, previousLineEnd))
		nextLineStart = view.text_point(lineNumber + forwardNumber[0], 0)
		nextLineEnd = view.text_point(lineNumber + forwardNumber[1], 0)
		nextLineContent = view.substr(sublime.Region(nextLineStart, nextLineEnd))
		currentLineContent = currentLineContent[:-1]
		previousLineContent = previousLineContent[:-1]
		nextLineContent = nextLineContent[:-1]
		propertyLineStart = None
		propertyLineEnd = None
		sortedProperties = None
		totalRegion = None
		properties = []


		def get_line ( direction, find, target ):
			nonlocal propertyLineStart
			nonlocal propertyLineEnd
			nonlocal sortedProperties
			nonlocal totalRegion

			lineStart = ''
			lineEnd = ''

			while lineNumber > 0:
				if direction == 'Backward':
					for i in range(len(backwardNumber)):
						backwardNumber[i] = backwardNumber[i] - 1

					lineStart = view.text_point(lineNumber + backwardNumber[0], 0)
					lineEnd = view.text_point(lineNumber + backwardNumber[1], 0)
				elif direction == 'Forward':
					for i in range(len(forwardNumber)):
						forwardNumber[i] = forwardNumber[i] + 1

					lineStart = view.text_point(lineNumber + forwardNumber[0], 0)
					lineEnd = view.text_point(lineNumber + forwardNumber[1], 0)

				region = sublime.Region(lineStart, lineEnd)
				lineContent = view.substr(region)
				lineContent = lineContent[:-1]

				if lineContent.endswith(find):
					if direction == 'Backward':
						propertyLineStart = view.text_point(lineNumber + backwardNumber[1], 0)
					elif direction == 'Forward':
						propertyLineEnd = view.text_point(lineNumber + forwardNumber[0], 0)

			sortedProperties = '\n'.join(properties)
			sortedProperties += '\n'

		get_line ( 'Backward', '{', 'selectorLine' )
		get_line ( 'Forward', '}', 'closingLine' )

		totalRegion = sublime.Region(propertyLineStart, propertyLineEnd)
		view.replace(edit, totalRegion, sortedProperties)


This doesn’t attempt to debug the problem, but have you considered simply using an existing plugin instead of writing your own?



Hello there, thanks you for the reference.

To be honest, I’m creating this plugin for personal use only. I’m using this chance to learn Python.

I’m not considering using the existing package because I don’t like something that is general which include many thing that is not needed on my personal use case. For example, there are many settings that can be customized, or any other features. These codes are not needed for me.

That’s why I want to create a simple plugin that suit my specific situation.



I solved the bug myself.