146 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			146 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import re
 | |
| import os
 | |
| import subprocess
 | |
| 
 | |
| try:
 | |
|     import simplejson
 | |
| except ImportError:
 | |
|     import json as simplejson
 | |
| 
 | |
| from base_linter import BaseLinter, TEMPFILES_DIR
 | |
| 
 | |
| CONFIG = {'language': 'CoffeeScript'}
 | |
| 
 | |
| 
 | |
| class Linter(BaseLinter):
 | |
|     coffeelint_config = {}
 | |
| 
 | |
|     def _test_executable(self, executable):
 | |
|         try:
 | |
|             args = [executable]
 | |
|             args.extend(self.test_existence_args)
 | |
|             subprocess.Popen(
 | |
|                 args,
 | |
|                 startupinfo=self.get_startupinfo(),
 | |
|                 stdout=subprocess.PIPE,
 | |
|                 stderr=subprocess.STDOUT
 | |
|             ).communicate()
 | |
|             return True
 | |
|         except OSError:
 | |
|             return False
 | |
| 
 | |
|     def get_executable(self, view):
 | |
|         if os.name == 'nt':
 | |
|             lint_command, coffee_command = (
 | |
|                 'coffeelint.cmd',
 | |
|                 'coffee.cmd',
 | |
|             )
 | |
|         else:
 | |
|             lint_command, coffee_command = (
 | |
|                 'coffeelint',
 | |
|                 'coffee',
 | |
|             )
 | |
| 
 | |
|         executable = None
 | |
| 
 | |
|         if self._test_executable(lint_command):
 | |
|             executable = lint_command
 | |
|             self.mode = 'coffeelint'
 | |
|         elif self._test_executable(coffee_command):
 | |
|             self.mode = 'coffee'
 | |
|             executable = coffee_command
 | |
| 
 | |
|         enabled = executable != None
 | |
| 
 | |
|         return (
 | |
|             enabled,
 | |
|             executable,
 | |
|             'using "%s" for executable' % executable if enabled else 'neither coffeelint nor coffee are available'
 | |
|         )
 | |
| 
 | |
|     def get_lint_args(self, view, code, filename):
 | |
|         if self.mode == 'coffeelint':
 | |
|             args = [
 | |
|                 '--stdin',
 | |
|                 '--nocolor',
 | |
|                 '--csv',
 | |
|             ]
 | |
| 
 | |
|             new_config = view.settings().get('coffeelint_options', {})
 | |
| 
 | |
|             if new_config != {}:
 | |
|                 # config based on tab/space and indentation settings set in
 | |
|                 # ST2 if these values aren't already set
 | |
|                 new_config['no_tabs']['level'] = new_config['no_tabs'].get(
 | |
|                     'level',
 | |
|                     'error' if view.settings().get('translate_tabs_to_spaces', False) else 'ignore'
 | |
|                 )
 | |
|                 new_config['indentation']['value'] = new_config['indentation'].get(
 | |
|                     'value',
 | |
|                     view.settings().get('tab_size', 8) if view.settings().get('translate_tabs_to_spaces', False) else 1
 | |
|                 )
 | |
| 
 | |
|                 if new_config != self.coffeelint_config:
 | |
|                     self.coffeelint_config = new_config
 | |
|                     self.write_config_file()
 | |
| 
 | |
|                 args += ['--file', self.coffeelint_config_file]
 | |
| 
 | |
|             return args
 | |
|         else:
 | |
|             return ('-s', '-l')
 | |
| 
 | |
|     def parse_errors(self, view, errors, lines, errorUnderlines,
 | |
|                      violationUnderlines, warningUnderlines, errorMessages,
 | |
|                      violationMessages, warningMessages):
 | |
| 
 | |
|         for line in errors.splitlines():
 | |
|             match = re.match(
 | |
|                 r'(?:stdin,\d+,error,)?Error: Parse error on line (?P<line>\d+): (?P<error>.+)',
 | |
|                 line
 | |
|             )
 | |
|             if match == None:
 | |
|                 match = re.match(
 | |
|                     r'stdin,(?P<line>\d+),(?P<type>[a-z]+),(?P<error>.*)',
 | |
|                     line
 | |
|                 )
 | |
|             if match == None:
 | |
|                 match = re.match(
 | |
|                     r'Error: (?P<error>.+) on line (?P<line>\d+)',
 | |
|                     line
 | |
|                 )
 | |
| 
 | |
|             if match:
 | |
|                 line_num, error_text = (
 | |
|                     int(match.group('line')),
 | |
|                     match.group('error'),
 | |
|                 )
 | |
| 
 | |
|                 try:
 | |
|                     error_type = match.group('type')
 | |
|                 except IndexError:
 | |
|                     error_type = None
 | |
| 
 | |
|                 self.add_message(
 | |
|                     line_num,
 | |
|                     lines,
 | |
|                     error_text,
 | |
|                     errorMessages if error_type == 'error' else warningMessages
 | |
|                 )
 | |
| 
 | |
|     def write_config_file(self):
 | |
|         """
 | |
|         coffeelint requires a config file to be able to pass configuration
 | |
|         variables to the program. this function writes a configuration file to
 | |
|         hold them and sets the location of the file
 | |
|         """
 | |
|         self.coffeelint_config_file = os.path.join(TEMPFILES_DIR, 'coffeelint.json')
 | |
|         temp_file = open(self.coffeelint_config_file, 'w')
 | |
|         temp_file.write(
 | |
|             simplejson.dumps(
 | |
|                 self.coffeelint_config,
 | |
|                 separators=(',', ':')
 | |
|             )
 | |
|         )
 | |
|         temp_file.close()
 |