Saturday, June 15, 2013

When I'm trying to code something I typically start with one problem and end up with fifteen, one of which will involve regular expressions. Today, I wanted to revamp my old Clayworks website as it's a stuck-in-1999 embarrassment (not quite geocities bad but bad enough).
  I'm using sublime text for my HTML editing but I found that I needed to re-format my old code and sublime-text doesn't have that functionality built in.
  Sublime-text does have rather nice python integration for easy plugin development so I did a little search, found this chap's website (http://www.bergspot.com/blog/2012/05/formatting-xml-in-sublime-text-2-xmllint/) and adapted his code, which makes use of xmllint (a unix tool but here's a windows version: http://code.google.com/p/xmllint/).
  My version doesn't need the text to be selected (if text is selected, only that part will be beautified) and will shows a pop-up error message and also takes you to the error line.

Anyhow, here's the code:



import sublime, sublime_plugin, subprocess

def find_lint_error_line(errString):    
  startpos = errString.find("-:")
  endpos = -1
  err_line = -1;
  if startpos != -1:
    startpos += 2
    endpos = errString.find(":", startpos)
    if endpos != -1:
      numstr = errString[startpos:endpos]        
      if numstr.isdigit():
        err_line = int(numstr)        
  return err_line
 
 
class TidyXmlLintCommand(sublime_plugin.TextCommand):
  def run(self, edit):
    command = "XMLLINT_INDENT='\t' xmllint --format --encode utf-8 -"
    self.view.set_status('self', "")
    #xmllint.view.set_status('Hey there Tim', "Hey hey hey")
    # help from http://www.sublimetext.com/forum/viewtopic.php?f=2&p=12451
    xmlRegion = sublime.Region(0, self.view.size())
    p = subprocess.Popen(command, bufsize=-1, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, shell=True)

    sel_regions = self.view.sel()
    selection = sel_regions[0]
    sel_region_count = len(selection)
    if sel_region_count == 0:      
      selection = xmlRegion
      
    result, err = p.communicate(self.view.substr(selection).encode('utf-8'))    
    
    if err != "":          
      self.view.set_status('xmllint', "xmllint: "+err)
      error_line = find_lint_error_line(err)
      #err.parse()
      #lines[] = parse("line {}", err)
      if error_line != -1:            
        pt = self.view.text_point(error_line, 0)

        self.view.sel().clear()
        self.view.sel().add(sublime.Region(pt))
        
        self.view.show_at_center(pt)
        #self.view.set_viewport_position((0, error_line * 16), True)      
      else:
        sublime.message_dialog('could not find error line')

      sublime.message_dialog('xmllint, error at line: '+ str(error_line) + " \n" + err )

      sublime.set_timeout(self.clear,10000)
    else:
      self.view.replace(edit, self.view.sel()[0], result.decode('utf-8'))
      sublime.set_timeout(self.clear,0)

  def clear(self):
    self.view.erase_status('xmllint')


And if you're wondering how I did that nice syntax colouring on the python code, check this out: SyntaxHighlighter

No comments:

Post a Comment