Sublime Forum

SublimeLint (Realtime lint highlighting)

#1

This plugin checks for errors in your code while you write it. It requires a fairly new beta of Sublime Text X or 2 (after Jon included thread/set_timeout support).

It currently has a rather featureful, platform-agnostic plugin for Python lint highlighting, and a basic PHP plugin which just runs “php -l” and highlights the error line if it finds one.

It’s pretty fast. It outlines all lines with errors, and underlines the specific error(s) on each line.
It shouldn’t slow down the UI, even with large files (there’s a current bug which might cause this sentence to be incorrect, most especially with php lint on windows, but it should be fixed very soon)

It’s not perfect.
It fails to underline the actual problem in a few places, like after the first line of multiline function arguments.
It recalculates the entire file after any changes are made instead of just the modified scope.
It chokes on Python parsing errors (completely invalid syntax will underline the offset provided by Python and give the error, but no other errors will be shown until you fix the syntax error)
Fixes for all of these are planned in a future update - I’m working on my own ast parser with scope awareness, real line/column offsets, simpler code, more checked cases, and faster parsing.

However… even the current iteration is infinitely better than waiting till you run/test the code to see errors.


See the project on GitHub
Download the latest GitHub master

You just need to put the file sublimelint_plugin.py and the folder sublimelint directly inside:

  • OS X: ~/Library/Application Support/Sublime Text 2/Packages/User/

  • Windows: %APPDATA%/Sublime Text 2/Packages/User/

  • Linux: ~/.Sublime Text 2/Packages/User/

edit: sentence revisions, added text for php

0 Likes

EmacsKillRing plugin for ST2?
Things that would make me buy Sublime Text 2
Some requests from russian community
#2

Looks cool! I’ll take a look at including the parser module under Linux.

Sublime Text 2 only acquires the GIL when it’s calling into Python directly, all other times Python threads are allowed to run. As a consequence of this, the the only thread-safe API function is sublime.set_timeout(), which schedules a function to be run by the main thread.

0 Likes

#3

Tried it out in Windows 7 64bit. Works like a charm :wink:

0 Likes

#4

the 1.x plugin used set_timeout but that implementation seemed to be pretty laggy on 2.
the current thread method works really well speed-wise on my macbook air (which is probably the near the slowest machine sublime will run on sans a netbook)

I only have problems with really long files (this 2k+ python file lines lags sometimes) - I probably won’t be able to fix this until I finish my own ast where I have control over more things and can just regenerate a single scope at a time.

even with this huge file, it only looks like I get crashing after reloading the module itself a few times

0 Likes

#5

Tried at Ubuntu Linux 10.10. No chances.
Best result with “export PYTHONPATH=/home/iorlas/apps/Sublime\ Text\ 2” + “ln -s /usr/lib/python2.6/lib-dynload/parser.so parser.so” in app dir:
Reloading plugin /home/iorlas/.Sublime Text 2/Packages/User/sublimeflakes.py
Traceback (most recent call last):
File “/home/iorlas/apps/Sublime Text 2/sublime_plugin.py”, line 34, in reload_plugin
m = import(modulename)
File “./sublimeflakes.py”, line 2, in
import os, sys, compiler, re
File “.\compiler_init_.py”, line 27, in
File “.\compiler\transformer.py”, line 29, in
ImportError: /home/iorlas/apps/Sublime Text 2/parser.so: undefined symbol: _Py_ZeroStruct

This is symbol, which can be found in the core lib of python or in python itself.
Using find, grep and objdump, i’ve found this files to prove this thoughts:
/usr/lib/wingide4.0/bin/PyCore/python: file format elf64-x86-64
/usr/lib/python2.6/config/libpython2.6.so: file format elf64-x86-64

I dont know what is “ZeroStruct”, but it’s suppose to be a something, what needs to be in core => need to wait for program developer. Anyway, we need to wait for “the Creator Voice”.
Also, it is so dangerous to see that on linux:

File “.**compiler**init.py”

It can be easier, if “somebody” will open sources or start to work with community.

0 Likes

#6

Version 20110130 of Sublime Text 2 should now allow the parser module to be imported on all platforms.

0 Likes

#7

Yay! Now “flakes” works perfectly. Waiting an author of plugin for new version and “flakes”.

0 Likes

#8

[quote=“Iorlas”]Also, it is so dangerous to see that on linux:

File “.\compiler_init_.py”[/quote]

that’s a python module (which comes with python itself) for byte-compiling python code. don’t know how you find that dangerous - python itself does this already every time you run a script.

not sure what you mean by this

0 Likes

#9

[quote=“lunixbochs”]

[quote=“Iorlas”]Also, it is so dangerous to see that on linux:

File “.\compiler_init_.py”[/quote]

that’s a python module (which comes with python itself) for byte-compiling python code. don’t know how you find that dangerous - python itself does this already every time you run a script.

not sure what you mean by this[/quote]

Oh, it is due breaking of bold in quotes :C I mean a back-slashes in the path. I see a 4 lines: 2 with slashes and 2 with back-slashes, but all of 'em as python native error message +_+

Waiting an author of plugin for new version
We want more features, we want stable version, i mean.
and “flakes”.
I call features of SublimeFlakes as “flakes”, just a joke :laughing:

0 Likes

#10

Ive started working on a fork of this. I’m awaiting a response from the author, but if I don’t hear back from him I’ll go ahead and setup a GitHub repo which includes the changes.

So far I’ve swapped it to use a newer/faster version of PyFlakes (which we maintain at DISQUS), and I’m working on better integration of the actual errors so it’s a bit more visible. I believe Sublime Text 2’s API isnt quite fully fleshed out yet, so it’s likely that this wont be too much better until it is.

0 Likes

#11

It took me a bit to figure out how to run the plugin with the directions given here. I was about to ask for more explicit directions, but then I figured it out, so I might as well say what I did for anyone else who’s confused.

If you unzip the file using Finder, it gives you a folder called “sublimeflakes_3-3”. If you put that folder in ~/Library/Application Support/Sublime Text 2/Packages/User/, nothing happens. You need to put the contents of that folder, which are “pyflakes” and “sublimeflakes.py”, in ~/Library/Application Support/Sublime Text 2/Packages/User/.

0 Likes

#12

This looks promising. I can’t get it to work though. I’m using version 20110203 of ST2 on Windows 7.
I can see a sublimeflakes.pyc getting created when I start Sublime Text.

After I’ve started Sublime Text 2 I can see this at the end of the console:

loaded 919 snippets
Unhandled exception in thread started by <function validate_runner at 0x0241EBF0>
Traceback (most recent call last):
  File ".\sublimeflakes.py", line 232, in validate_runner
  File ".\sublimeflakes.py", line 75, in validate
RuntimeError: Must call on main thread, consider using sublime.set_timeout(function, timeout)

Nothing happens when I edit a pythonfile.

0 Likes

#13

This is due to a change in 20110203 which enforces that plugins are only allowed to call API functions from the main thread.

0 Likes

#14

Nothing happens when I edit my python code. :frowning: I’m using the latest Sublime 2 for Mac.

0 Likes

#15

I’ve hacked the code a bit so that it works for me. Hope that it helps.
sublimeflakes.py.zip (2.8 KB)

0 Likes

#16

oh nice, we can use set_timeout from a thread? I’ll include that in the master version until I craft a better solution.

zeeg: I shot you a PM back, looks like this forum might not send emails for PM notifications

everyone else:
it’s now on github with a few fixes and more updates to come: github.com/lunixbochs/sublimelint

0 Likes

#17

It works! Great! Thanks!

0 Likes

#18

Works great for me too (Ubuntu 10.10 64bit):

cd ~/.Sublime\ Text\ 2/Packages
git clone https://github.com/lunixbochs/sublimelint.git
0 Likes

#19

You can also put it in its own folder: …]/Packages/SublimeFlakes/ instead of …]/Packages/User/

0 Likes

#20

OK this is a seriously awesome plugin.

I decided to extend it to PHP so that it uses the PHP in your path to do a lint check on the source. It doesn’t give you the nice granularity of errors, but it will immediately highlight a line when it has a problem, which is incredibly useful for me (once we can extend the Autocomplete API I’m pretty sure I can make ST2 my full time PHP editor).

Here is my file, I just used your python.py module as an example. It is called php.py

[code]# php.py - sublimelint package for checking php files

start code to actually work with PHP and lint check input

import subprocess, os, tempfile

def check(codeString, filename):
info = None
if os.name == ‘nt’:
info = subprocess.STARTUPINFO()
info.dwFlags |= subprocess.STARTF_USESHOWWINDOW
info.wShowWindow = subprocess.SW_HIDE
tmpFile = tempfile.NamedTemporaryFile(delete=False)
tmpFileName = tmpFile.name
tmpFile.write(codeString)
tmpFile.close()
result = subprocess.Popen(‘php’, ‘-l’, tmpFileName], stdout=subprocess.PIPE, startupinfo=info).communicate()[0]
os.unlink(tmpFileName)
return result, tmpFileName

start sublimelint php plugin

import re
all = ‘run’, ‘language’]
language = ‘PHP’

def run(code, view, filename=‘untitled’):
errors, tmpFile = check(code, filename)

lines = set()
underline = ] # leave this here for compatibility with original plugin

errorMessages = {}
def addMessage(lineno, message):
	message = str(message)
	if lineno in errorMessages:
		errorMessages[lineno].append(message)
	else:
		errorMessages[lineno] = [message]

m = re.search(r"on line (\d+)", errors);
if m:
	lineno = int(m.group(1))
	lineno -= 1
	lines.add(lineno)		
	errorLines = errors.splitlines();
	tmpFile = tmpFile.replace("\\", "\\\\")
	m2 = re.search(r"(.*) in " + tmpFile + " on line \d+", errorLines[1])		
	addMessage(lineno, m2.group(1))

return underline, lines, errorMessages, True

[/code]

As well I decided to implement one of your TODO lists, the automatic loading of modules based on their file names. Here is the head of my file (until drawType):

import sublime, sublime_plugin
import os, glob

# todo:
# * fix lag

languages = ]

# fix for __import__ returning 'sublimelint.modules.foo'.split('.')[0] as the module name
def importhelper(name):
    mod = __import__(name)
    components = name.split('.')
    for comp in components[1:]:
        mod = getattr(mod, comp)
    return mod

# auto include our modules
for modfile in glob.glob('sublimelint/modules/*.py') :
	if '__init__' in modfile: continue	
	modname = os.path.basename(modfile).split('.')[0]
	vars()[modname] = importhelper('sublimelint.modules.'+ modname)	
	languages.append(vars()[modname])

also delete line 10 in: github.com/lunixbochs/sublimeli … _plugin.py

and it should work.

Sorry if the code is garbage, this is my first foray ever into Python, definitely an interesting language.

0 Likes