Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial commit of the PHP CodeSniffer Sublime Text 2 Plugin

  • Loading branch information...
commit 162d2456291181010e9ae9ebf536a5711db7ca43 0 parents
@benmatselby authored
10 Context.sublime-menu
@@ -0,0 +1,10 @@
+[
+ { "caption": "-" },
+ {
+ "caption": "PHP CodeSniffer",
+ "children":
+ [
+ { "command": "phpcs_sniff_this_file" }
+ ]
+ }
+]
6 Default.sublime-commands
@@ -0,0 +1,6 @@
+[
+ {
+ "caption": "PHP CodeSniffer: Sniff This File",
+ "command": "phpcs_sniff_this_file"
+ }
+]
29 LICENSE.md
@@ -0,0 +1,29 @@
+New BSD License
+===============
+
+Copyright (c) 2012, Ben Selby and contributors
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+* Neither the names of the copyright holders nor the names of its
+ contributors may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
46 Main.sublime-menu
@@ -0,0 +1,46 @@
+[
+ {
+ "id": "tools",
+ "caption": "Tools",
+ "children":
+ [
+ {
+ "caption": "PHP CodeSniffer...",
+ "command": "show_overlay",
+ "args": {"overlay": "command_palette", "text": "PHP CodeSniffer: " }
+ }
+ ]
+ },
+ {
+ "caption": "Preferences",
+ "mnemonic": "n",
+ "id": "preferences",
+ "children":
+ [
+ {
+ "caption": "Package Settings",
+ "mnemonic": "P",
+ "id": "package-settings",
+ "children":
+ [
+ {
+ "caption": "PHP CodeSniffer",
+ "children":
+ [
+ {
+ "command": "open_file",
+ "args": {"file": "${packages}/Phpcs/phpcs.sublime-settings"},
+ "caption": "Settings – Default"
+ },
+ {
+ "command": "open_file",
+ "args": {"file": "${packages}/User/phpcs.sublime-settings"},
+ "caption": "Settings – User"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+]
35 README.md
@@ -0,0 +1,35 @@
+Sublime PHP CodeSniffer
+=======================
+
+This plugin adds PHP CodeSniffer support to Sublime Text 2.
+
+Installation
+------------
+
+Use Sublime Text 2's [Package Control](http://wbond.net/sublime_packages/package_control) (Preferences -> Package Control -> Install Package -> PHP CodeSniffer) to install this plugin.
+
+PHP CodeSniffer Support For Sublime Text 2
+------------------------------------------
+
+This plugin adds support for running PHP CodeSniffer from inside Sublime Text 2.
+
+Right-click in the editor to:
+
+* Sniff the current file
+
+Right-click in the side-bar to:
+
+* Sniff all files in a folder
+
+You can also open up the Command Palette (CTRL + SHIFT + P on Linux), and type
+'PHP CodeSniffer' to see what you can do with PHP CodeSniffer in the currently open file.
+
+PHP CodeSniffer support is based on:
+[PHPUnit plugin](https://github.com/stuartherbert/sublime-phpunit) which is based on
+[Ruby Tests plugin](https://github.com/maltize/sublime-text-2-ruby-tests)_
+
+
+Contributions Welcome
+---------------------
+
+Requests for features, and pull requests with patches, are most welcome :)
11 Side Bar.sublime-menu
@@ -0,0 +1,11 @@
+[
+ { "caption": "-" },
+ {
+ "caption": "PHP CodeSniffer",
+ "children":
+ [
+ { "command": "phpcs_sniff_this_file", "args": { "paths": [] } },
+ { "command": "phpcs_sniff_all_files", "args": { "paths": [] } }
+ ]
+ }
+]
256 phpcs.py
@@ -0,0 +1,256 @@
+import datetime
+import functools
+import os
+import re
+import subprocess
+import time
+import thread
+import sublime
+import sublime_plugin
+
+
+class Pref:
+ def load(self):
+ settings = sublime.load_settings('phpcs.sublime-settings')
+ Pref.phpcs_additional_args = settings.get('phpcs_additional_args', {})
+ Pref.phpcs_execute_on_save = settings.get('phpcs_execute_on_save', {})
+
+Pref().load()
+
+
+# the AsyncProcess class has been cribbed from:
+# https://github.com/maltize/sublime-text-2-ruby-tests/blob/master/run_ruby_test.py
+class AsyncProcess(object):
+ def __init__(self, cmd, listener):
+ self.cmd = cmd
+ self.listener = listener
+ print "DEBUG_EXEC: " + self.cmd
+ self.proc = subprocess.Popen([self.cmd], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ if self.proc.stdout:
+ thread.start_new_thread(self.read_stdout, ())
+ if self.proc.stderr:
+ thread.start_new_thread(self.read_stderr, ())
+
+ def read_stdout(self):
+ while True:
+ data = os.read(self.proc.stdout.fileno(), 2 ** 15)
+ if data != "":
+ sublime.set_timeout(functools.partial(self.listener.append_data, self.proc, data), 0)
+ else:
+ self.proc.stdout.close()
+ self.listener.is_running = False
+ break
+
+ def read_stderr(self):
+ while True:
+ data = os.read(self.proc.stderr.fileno(), 2 ** 15)
+ if data != "":
+ sublime.set_timeout(functools.partial(self.listener.append_data, self.proc, data), 0)
+ else:
+ self.proc.stderr.close()
+ self.listener.is_running = False
+ self.listener.append_data(self.proc, "\n--- PROCESS COMPLETE ---")
+ break
+
+
+# the StatusProcess class has been cribbed from:
+# https://github.com/maltize/sublime-text-2-ruby-tests/blob/master/run_ruby_test.py
+class StatusProcess(object):
+ def __init__(self, msg, listener):
+ self.msg = msg
+ self.listener = listener
+ thread.start_new_thread(self.run_thread, ())
+
+ def run_thread(self):
+ progress = ""
+ while True:
+ if self.listener.is_running:
+ if len(progress) >= 10:
+ progress = ""
+ progress += "."
+ sublime.set_timeout(functools.partial(self.listener.update_status, self.msg, progress), 0)
+ time.sleep(1)
+ else:
+ break
+
+
+class OutputView(object):
+ def __init__(self, name, window):
+ self.output_name = name
+ self.window = window
+
+ def show_output(self):
+ self.ensure_output_view()
+ self.window.run_command("show_panel", {"panel": "output." + self.output_name})
+
+ def show_empty_output(self):
+ self.ensure_output_view()
+ self.clear_output_view()
+ self.show_output()
+
+ def ensure_output_view(self):
+ if not hasattr(self, 'output_view'):
+ self.output_view = self.window.get_output_panel(self.output_name)
+
+ def clear_output_view(self):
+ self.ensure_output_view()
+ self.output_view.set_read_only(False)
+ edit = self.output_view.begin_edit()
+ self.output_view.erase(edit, sublime.Region(0, self.output_view.size()))
+ self.output_view.end_edit(edit)
+ self.output_view.set_read_only(True)
+
+ def append_data(self, proc, data):
+ str = data.decode("utf-8")
+ str = str.replace('\r\n', '\n').replace('\r', '\n')
+
+ selection_was_at_end = (len(self.output_view.sel()) == 1
+ and self.output_view.sel()[0]
+ == sublime.Region(self.output_view.size()))
+ self.output_view.set_read_only(False)
+ edit = self.output_view.begin_edit()
+ self.output_view.insert(edit, self.output_view.size(), str)
+ if selection_was_at_end:
+ self.output_view.show(self.output_view.size())
+ self.output_view.end_edit(edit)
+ self.output_view.set_read_only(True)
+
+
+class CommandBase:
+ def __init__(self, window):
+ self.window = window
+
+ def show_output(self):
+ if not hasattr(self, 'output_view'):
+ self.output_view = OutputView('phpcs', self.window)
+
+ self.output_view.show_output()
+
+ def show_empty_output(self):
+ if not hasattr(self, 'output_view'):
+ self.output_view = OutputView('phpcs', self.window)
+
+ self.output_view.clear_output_view()
+ self.output_view.show_output()
+
+ def start_async(self, caption, executable):
+ self.is_running = True
+ self.proc = AsyncProcess(executable, self)
+ StatusProcess(caption, self)
+
+ def append_data(self, proc, data):
+ self.output_view.append_data(proc, data)
+
+ def update_status(self, msg, progress):
+ sublime.status_message(msg + " " + progress)
+
+
+class ActiveFile:
+ searched_folders = {}
+ search_results_cache = {}
+ last_search_time = None
+
+
+class ActiveView(ActiveFile):
+ def is_php_buffer(self):
+ # is this a PHP buffer?
+ if re.search('.+\PHP.tmLanguage', self.view.settings().get('syntax')):
+ return True
+ return False
+
+ def file_name(self):
+ return self.view.file_name()
+
+
+class ActiveWindow(ActiveFile):
+ def file_name(self):
+ if hasattr(self, '_file_name'):
+ return self._file_name
+
+ return None
+
+ def determine_filename(self, args=[]):
+ if len(args) == 0:
+ active_view = self.window.active_view()
+ filename = active_view.file_name()
+ else:
+ filename = args[0]
+
+ self._file_name = filename
+
+ def is_php_buffer(self):
+ ext = os.path.splitext(self.file_name())[1]
+ if ext == 'php':
+ return True
+ return False
+
+
+class PhpcsTextBase(sublime_plugin.TextCommand, ActiveView):
+ def run(self, args):
+ print 'Not implemented'
+
+
+class PhpcsCommand(CommandBase):
+ def run(self, path):
+ self.show_empty_output()
+
+ if os.path.isdir(path):
+ dir = path
+ else:
+ dir = os.path.dirname(path)
+ target = path
+
+ cmd = "cd '" + dir + "' && phpcs"
+
+ # Add the additional arguments from the settings file to the command
+ for key, value in Pref.phpcs_additional_args.items():
+ cmd = cmd + " " + key
+ if value != "":
+ cmd = cmd + "=" + value
+
+ cmd = cmd + " '" + path + "'"
+
+ self.append_data(self, "$ " + cmd + "\n")
+ self.start_async("Running PHP CodeSniffer", cmd)
+
+
+class PhpcsSniffThisFile(PhpcsTextBase):
+ def run(self, args):
+ print "Running PhpcsSniffThisFile"
+
+ cmd = PhpcsCommand(self.view.window())
+ cmd.run(self.view.file_name())
+
+ def description(self):
+ if not self.is_php_buffer():
+ return "Invalid file format"
+ else:
+ return 'Sniff this file...'
+
+ def is_enabled(self):
+ if not self.is_php_buffer():
+ return False
+ return True
+
+class PhpcsWindowBase(sublime_plugin.WindowCommand, ActiveWindow):
+ def run(self, paths=[]):
+ print "not implemented"
+
+class PhpcsSniffAllFiles(PhpcsWindowBase):
+ def run(self, paths=[]):
+
+ cmd = PhpcsCommand(self.window)
+ cmd.run(paths[0])
+
+ def description(self):
+ return 'Sniff all files...'
+
+
+class PhpcsEventListener(sublime_plugin.EventListener):
+ def on_post_save(self, view):
+
+ if Pref.phpcs_execute_on_save == True:
+
+ if re.search('.+\PHP.tmLanguage', view.settings().get('syntax')):
+
+ view.window().run_command("phpcs_sniff_this_file")
7 phpcs.sublime-settings
@@ -0,0 +1,7 @@
+{
+ "phpcs_additional_args":
+ {
+ "--report": "checkstyle"
+ },
+ "phpcs_execute_on_save": true
+}
Please sign in to comment.
Something went wrong with that request. Please try again.