Advertisement
Guest User

Untitled

a guest
Apr 18th, 2016
454
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 20.74 KB | None | 0 0
  1. import sublime
  2. import sublime_plugin
  3. import subprocess
  4. import os
  5. import re
  6.  
  7. import tempfile
  8. import codecs
  9.  
  10. import threading
  11.  
  12.  
  13. def plugin_loaded():
  14.     settings.update()
  15.     start_thread()
  16.    
  17. def start_thread(view):
  18.     # Tn theory, you would do your "stuff" on this view object,
  19.     # but you utilize "active_view()" in other places of the code instead,
  20.     # notably ClanglinterContext.update. I'm not going to refactor that.
  21.     clanglinter_thread = ClanglinterThread()
  22.     clanglinter_thread.start()
  23.        
  24.     # This is the second case: (but it also doesn't work)
  25.     #sublime.set_timeout_async(AsyncClanglinter.clang_thread(self, edit), 0)
  26.  
  27. # The code below is for 2nd case (using sublime.set_timeout_async), but is doesn't work
  28. #class AsyncClanglinter():
  29. #   def clang_thread(self, edit):
  30. #       settings.update()
  31. #       if settings.get('enable'):
  32. #           context.update()
  33. #           analyzed_file_content = utils.get_view_content(context.get('view'))
  34. #           temp_file_object = utils.create_temp_file()
  35. #           utils.write_temp_file(temp_file_object, analyzed_file_content)
  36. #          
  37. #           cmd = utils.get_full_cmd(settings.get('clanglinter_cmd'),
  38. #                                   temp_file_object.name,
  39. #                                   settings.get('project_settings'))
  40. #          
  41. #           clang_output = utils.clang_launch(cmd)
  42. #          
  43. #           parser.update(clang_output)
  44. #           parser_output = parser.get_format_output()
  45. #          
  46. #           ui.regions_clear()
  47. #           if parser_output:
  48. #               ui.regions_create()
  49. #               ui.output_panel_clear(edit)
  50. #               ui.output_panel_insert_lines(edit, parser_output)
  51. #               ui.output_panel_show()
  52. #           else:
  53. #               ui.output_panel_clear(edit)
  54. #               ui.output_panel_hide()
  55.  
  56. class ClanglinterThread(threading.Thread):
  57.     def run(self):
  58.         settings.update()
  59.         if settings.get('enable'):
  60.             context.update()
  61.             analyzed_file_content = utils.get_view_content(context.get('view'))
  62.             temp_file_object = utils.create_temp_file()
  63.             utils.write_temp_file(temp_file_object, analyzed_file_content)
  64.            
  65.             cmd = utils.get_full_cmd(settings.get('clanglinter_cmd'),
  66.                                     temp_file_object.name,
  67.                                     settings.get('project_settings'))
  68.            
  69.             clang_output = utils.clang_launch(cmd)
  70.            
  71.             parser.update(clang_output)
  72.             parser_output = parser.get_format_output()
  73.            
  74.             ui.regions_clear()
  75.             if parser_output:
  76.                 ui.regions_create()
  77.                 self.sublime.active_window().run_command('output_panel_clear')
  78.                 self.sublime.active_window().run_command('output_panel_insert_lines', {'chars' : parser_output})
  79.                 ui.output_panel_show()
  80.             else:
  81.                 self.sublime.active_window().run_command('output_panel_clear')
  82.                 ui.output_panel_hide()
  83.  
  84. # output_panel_clear
  85. class OutputPanelClearCommand(sublime_plugin.WindowCommand):
  86.     def run(self):
  87.         view = self.window.create_output_panel("clanglinter_panel")
  88.         #view.set_read_only(False)
  89.         view.run_command('select_all')
  90.         view.run_command('left_delete')
  91.         #view.set_read_only(True)
  92.  
  93. # output_panel_insert_lines
  94. class OutputPanelInsertLinesCommand(sublime_plugin.WindowCommand):
  95.     def run(self, **kwargs):
  96.         parser_output = kwargs['chars']
  97.        
  98.         view = self.window.create_output_panel("clanglinter_panel")
  99.         view.set_name('clanglinter_panel')
  100.        
  101.         #self.output_panel_view = view
  102.        
  103.         view.settings().set("line_numbers", True)
  104.         view.settings().set("gutter", True)
  105.         view.settings().set("word_wrap", False)
  106.         view.settings().set("scroll_past_end", False)
  107.         view.settings().set("highlight_line", True)
  108.         #view.settings().set("ruler", False)
  109.         #view.settings().set("result_file_regex",
  110.         #                    "^(^\S.*\.\w+):(\d+):(\d+): (\w+ ?\w+?): (.*)$")
  111.        
  112.         #view.settings().set("color_scheme",
  113.         #                    "Packages/ClangLinter/ClangLinter_output_panel.hidden-tmTheme")
  114.        
  115.         view.set_syntax_file(
  116.             "Packages/ClangLinter/ClangLinter_output_panel.hidden-tmLanguage")
  117.        
  118.         view.set_read_only(False)
  119.         view.run_command('append', {'characters': parser_output})
  120.         view.set_read_only(True)
  121.  
  122.  
  123. class ClanglinterSettings():
  124.     def update(self):
  125.         window = sublime.active_window()
  126.         view = sublime.active_window().active_view()
  127.        
  128.         all_settings = {}
  129.        
  130.         plugin_settings = sublime.load_settings("ClangLinter.sublime-settings")
  131.        
  132.         all_settings['enable'] = plugin_settings.get('enable')
  133.         all_settings['debug'] = plugin_settings.get('debug')
  134.        
  135.         all_settings['analyze_on_save_only'] = (
  136.             plugin_settings.get('analyze_on_save_only'))
  137.        
  138.         all_settings['show_output_panel'] = (
  139.             plugin_settings.get('show_output_panel'))
  140.        
  141.         all_settings['clanglinter_extensions'] = (
  142.             plugin_settings.get('clanglinter_extensions'))
  143.        
  144.         all_settings['clanglinter_syntaxes'] = (
  145.             plugin_settings.get('clanglinter_syntaxes'))
  146.        
  147.         all_settings['clanglinter_cmd'] = (
  148.             plugin_settings.get('clanglinter_cmd'))
  149.        
  150.         all_settings['project_settings'] = self.__get_project_settings()
  151.        
  152.         self.all_settings = all_settings
  153.    
  154.     def get(self, setting_name):
  155.         if setting_name in self.all_settings:
  156.             return self.all_settings[setting_name]
  157.         else:
  158.             if self.all_settings['debug']:
  159.                 print('ClangLinter debug. Settings ERROR:', self.all_settings)
  160.             return None
  161.    
  162.     def __get_project_settings(self):
  163.         # try if any project is open, except - no project is open
  164.         try:
  165.             project_data = sublime.active_window().project_data()
  166.             project_file_name = sublime.active_window().project_file_name()
  167.            
  168.             project_settings = (
  169.                     project_data['settings']['clanglinter_cmd_options'])
  170.            
  171.             project_path = os.path.dirname(project_file_name)
  172.            
  173.             for i in range(len(project_settings)):
  174.                 project_settings[i] = project_settings[i].replace(
  175.                     '${project_path}', project_path)
  176.                 # project_settings[i] = project_settings[i].replace("\\", "/")
  177.         except:
  178.             project_settings = []
  179.        
  180.         return project_settings
  181.  
  182.  
  183. class ClanglinterContext():
  184.     def __init__(self):
  185.         self.all_context = {}
  186.    
  187.     def update(self):
  188.         window = sublime.active_window()
  189.         view = sublime.active_window().active_view()
  190.        
  191.         all_context = {}
  192.        
  193.         all_context['view'] = view
  194.         all_context['window'] = window.id()
  195.         all_context['group'] = window.active_group()
  196.         all_context['syntax'] = view.settings().get('syntax')
  197.         #all_context['encoding'] = view.encoding()
  198.        
  199.         try:
  200.             all_context['path_basename_extension'] = view.file_name()
  201.         except:
  202.             all_context['path_basename_extension'] = ''
  203.        
  204.         try:
  205.             all_context['path'] = os.path.dirname(all_context['path_basename_extension'])
  206.         except:
  207.             all_context['path'] = ''
  208.        
  209.         try:
  210.             all_context['basename'] = os.path.basename(all_context['path_basename_extension'])
  211.         except:
  212.             all_context['basename'] = ''
  213.        
  214.         try:
  215.             all_context['extension'] = os.path.splitext(all_context['path_basename_extension'])[1][1:]
  216.         except:
  217.             all_context['extension'] = ''
  218.        
  219.         if tempfile.gettempdir():
  220.             temp_dir_path = tempfile.gettempdir() + "\\Clanglinter"
  221.             if os.path.isdir(temp_dir_path) == False:
  222.                 os.mkdir(temp_dir_path)
  223.             all_context['temp_dir_path'] = temp_dir_path
  224.         else:
  225.             all_context['temp_dir_path'] = ''
  226.        
  227.         self.all_context = all_context
  228.    
  229.     def get(self, context_name):
  230.         if context_name in self.all_context:
  231.             return self.all_context[context_name]
  232.  
  233.  
  234. class ClanglinterUtils():
  235.     def clang_launch(self, cmd):
  236.         utils.print_debug("Clang cmd:", cmd)
  237.        
  238.         clang_process = subprocess.Popen(
  239.             cmd,
  240.             # cwd=,
  241.             bufsize=-1,
  242.             stdin=subprocess.PIPE,
  243.             stdout=subprocess.PIPE,
  244.             stderr=subprocess.PIPE,
  245.             shell=True,
  246.             universal_newlines=True)
  247.        
  248.         # output_errors, output_info = p.communicate()
  249.         output_errors = clang_process.stderr.read()
  250.         output_info = clang_process.stdout.read()
  251.        
  252.         utils.print_debug("Clang output:\n", output_errors + output_info)
  253.         return output_errors + output_info
  254.    
  255.     def check_extension(self, file_extension):
  256.         if file_extension in settings.get('clanglinter_extensions'):
  257.             return True
  258.         else:
  259.             utils.print_debug(
  260.                 'This file does not satisfy the extension. Current extension',
  261.                 file_extension)
  262.             return False
  263.    
  264.     def check_syntax(self, active_view):
  265.         syntax_full_name = active_view.settings().get('syntax')
  266.         syntax_basename = os.path.basename(syntax_full_name)
  267.        
  268.         if syntax_basename in settings.get('clanglinter_syntaxes'):
  269.             return True
  270.         else:
  271.             utils.print_debug(
  272.                 'This file does not satisfy the syntax. Current syntax:',
  273.                 syntax_basename)
  274.             return False
  275.    
  276.     def create_temp_file(self):
  277.         window = sublime.active_window()
  278.        
  279.         temp_file_basename = "temp_%s" % window.id()
  280.         temp_file_extension = context.get('extension')
  281.        
  282.         #file_object = codecs.open(context.get('temp_dir_path') + \
  283.         #                           temp_file_basename + '.' + \
  284.         #                           temp_file_extension, 'w+', 'utf-8-sig')
  285.        
  286.         file_object = open(context.get('temp_dir_path') + \
  287.                             temp_file_basename + '.' + \
  288.                             temp_file_extension, 'w')
  289.        
  290.         return file_object
  291.    
  292.     #def read_file(self, file_full_name):
  293.     #   file_object = open(file_full_name, 'r', encoding="utf8")
  294.     #   return file_object.read()
  295.  
  296.     def get_view_content(self, active_view):
  297.         return active_view.substr(sublime.Region(0, active_view.size()))
  298.    
  299.     def write_temp_file(self, file_object, string):
  300.         string.encode('utf-8')
  301.         file_object.write(string)
  302.         file_object.close()
  303.    
  304.     def get_full_cmd(self, clanglinter_cmd, temp_file_object_full_name, project_settings):
  305.        
  306.         clanglinter_cmd.append(temp_file_object_full_name)
  307.        
  308.         for option in project_settings:
  309.             clanglinter_cmd.append(option)
  310.        
  311.         return clanglinter_cmd
  312.    
  313.     def print_debug(self, part_1, part_2=''):
  314.         if settings.get('debug'):
  315.             print("ClangLinter debug.", part_1, part_2)
  316.  
  317.  
  318. class ClanglinterParser():
  319.     def update(self, input):
  320.         format_output = ''
  321.         parameters_list = []
  322.        
  323.         for line in range(len(input.split('\n'))):
  324.             temp_line = input.split('\n')[line]
  325.            
  326.             parameters = {}
  327.             regex = re.search(
  328.                 r'^(^\S.*\.\w+):(\d+):(\d+): (\w+ ?\w+?): (.*)$', temp_line)
  329.            
  330.             if regex is not None:
  331.                 parameters['file'] = regex.group(1)
  332.                
  333.                 # replace temp file to context file
  334.                 if context.get('temp_dir_path') in parameters['file']:
  335.                     parameters['file'] = context.get('path_basename_extension')
  336.                
  337.                 parameters['line'] = regex.group(2)
  338.                 parameters['column'] = regex.group(3)
  339.                 parameters['flag'] = regex.group(4)
  340.                 parameters['description'] = regex.group(5)
  341.                
  342.                 format_output += \
  343.                     parameters['file'] + '  ' \
  344.                     + parameters['line'] + ':' \
  345.                     + parameters['column'] + '  ' \
  346.                     + parameters['flag'] + ': ' \
  347.                     + parameters['description'] + '\n'
  348.                
  349.                 parameters['line'] = int(parameters['line'])
  350.                 parameters['column'] = int(parameters['column'])
  351.                
  352.                 parameters_list.append(parameters)
  353.                
  354.         self.format_output = format_output
  355.         self.parameters_list = parameters_list
  356.    
  357.     def get_parameters(self):
  358.         return self.parameters_list
  359.    
  360.     def get_format_output(self):
  361.         return self.format_output
  362.    
  363.     #def get_true_column(self, view, line, column):
  364.     #   tab_size = view.settings().get('tab_size')
  365.     #  
  366.     #   point = view.text_point(line - 1, column - 1)
  367.     #   print('POINT:', point)
  368.     #   line_region = view.line(point)
  369.     #   print('line_region')
  370.     #   raw_line = view.substr(line_region)
  371.     #   print('RAW LINE:', raw_line)
  372.     #  
  373.     #   parser.get_true_column(view, line, column)
  374.     #   point = view.text_point(line, column)
  375.     #   view.sel().clear()
  376.     #   view.sel().add(sublime.Region(10))
  377.     #   print(point)
  378.    
  379.     #def get_true_encoding_name(self, input_encoding_name):
  380.     #   possible_encoding_names = {'UTF-8': 'utf-8', 'UTF-16 LE': ''}
  381.  
  382.  
  383. class UserInterface():
  384.     def output_panel_insert_lines(self, edit, parser_output):
  385.         window = sublime.active_window()
  386.         view = window.create_output_panel("clanglinter_panel")
  387.         view.set_name('clanglinter_panel')
  388.        
  389.         #self.output_panel_view = view
  390.        
  391.         view.settings().set("line_numbers", True)
  392.         view.settings().set("gutter", True)
  393.         view.settings().set("word_wrap", False)
  394.         view.settings().set("scroll_past_end", False)
  395.         view.settings().set("highlight_line", True)
  396.         #self.view.settings().set("ruler", False)
  397.         #self.view.settings().set("result_file_regex",
  398.         #                       "^(^\S.*\.\w+):(\d+):(\d+): (\w+ ?\w+?): (.*)$")
  399.        
  400.         #self.view.settings().set("color_scheme",
  401.         #                       "Packages/ClangLinter/ClangLinter_output_panel.hidden-tmTheme")
  402.        
  403.         view.set_syntax_file(
  404.             "Packages/ClangLinter/ClangLinter_output_panel.hidden-tmLanguage")
  405.        
  406.         view.set_read_only(False)
  407.         view.insert(edit, view.size(), parser_output)
  408.        
  409.         view.set_read_only(True)
  410.    
  411.     def output_panel_show(self):
  412.         sublime.active_window().run_command(
  413.             "show_panel", {"panel": "output.clanglinter_panel"})
  414.    
  415.     def output_panel_hide(self):
  416.         sublime.active_window().run_command(
  417.             "hide_panel", {"panel": "output.clanglinter_panel"})
  418.    
  419.     def output_panel_clear(self, edit):
  420.         view = sublime.active_window().create_output_panel("clanglinter_panel")
  421.        
  422.         #self.view.set_read_only(False)
  423.         view.erase(edit, sublime.Region(0, view.size()))
  424.         #self.view.set_read_only(True)
  425.    
  426.     def regions_create(self):
  427.         view = sublime.active_window().active_view()
  428.        
  429.         region_error = []
  430.         region_warning = []
  431.         region_note = []
  432.        
  433.         scope_error = 'entity.name.tag'
  434.         scope_warning = 'entity.other.attribute-name'
  435.         scope_note = 'constant.other.symbol'
  436.         #print(sublime.active_window().active_view().file_name())
  437.         for line in range(len(parser.get_parameters())):
  438.             if parser.get_parameters()[line]['file'] == view.file_name():
  439.                 if parser.get_parameters()[line]['flag'] == 'error' or 'fatal error':
  440.                    
  441.                     temp_line = parser.get_parameters()[line]['line'] - 1
  442.                     temp_column = parser.get_parameters()[line]['column'] - 1
  443.                     point_error = view.text_point(temp_line, temp_column)
  444.                     region_error.append(view.line(point_error))
  445.                    
  446.                 if parser.get_parameters()[line]['flag'] == 'warning':
  447.                    
  448.                     temp_line = parser.get_parameters()[line]['line'] - 1
  449.                     temp_column = parser.get_parameters()[line]['column'] - 1
  450.                     point_warning = view.text_point(temp_line, temp_column)
  451.                     region_warning.append(view.line(point_warning))
  452.                    
  453.                 if parser.get_parameters()[line]['flag'] == 'note':
  454.                    
  455.                     temp_line = parser.get_parameters()[line]['line'] - 1
  456.                     temp_column = parser.get_parameters()[line]['column'] - 1
  457.                     point_note = view.text_point(temp_line, temp_column)
  458.                     region_note.append(view.line(point_note))
  459.                    
  460.         view.add_regions(
  461.             'clanglinter_note', region_note, scope_note, 'dot',
  462.             sublime.DRAW_OUTLINED)
  463.        
  464.         view.add_regions(
  465.             'clanglinter_warning', region_warning, scope_warning, 'dot',
  466.             sublime.DRAW_OUTLINED)
  467.        
  468.         view.add_regions(
  469.             'clanglinter_error', region_error, scope_error, 'dot',
  470.             sublime.DRAW_OUTLINED)
  471.    
  472.     def regions_output_panel(self, view, line):
  473.         region_output_panel = []
  474.        
  475.         view.set_read_only(False)
  476.        
  477.         point_output_panel = view.text_point(line, 0)
  478.         region_output_panel.append(
  479.             view.line(point_output_panel))
  480.        
  481.         view.add_regions(
  482.             'clanglinter_output_panel', region_output_panel, 'text', '',
  483.             sublime.DRAW_OUTLINED)
  484.        
  485.         view.set_read_only(True)
  486.    
  487.     def regions_clear(self):
  488.         view = sublime.active_window().active_view()
  489.         view.erase_regions('clanglinter_note')
  490.         view.erase_regions('clanglinter_warning')
  491.         view.erase_regions('clanglinter_error')
  492.        
  493. ui = UserInterface()
  494. settings = ClanglinterSettings()
  495. context = ClanglinterContext()
  496. utils = ClanglinterUtils()
  497. parser = ClanglinterParser()
  498.  
  499.  
  500. class SublimeEventListener(sublime_plugin.EventListener):
  501.     def __init__(self):
  502.         self.old_view = None
  503.         self.wait_for_loading = False
  504.    
  505.     def on_post_save_async(self, view):
  506.         window = sublime.active_window()
  507.        
  508.         if window.id() == context.get('window'):
  509.             if (utils.check_extension(os.path.splitext(view.file_name())[1][1:]) and
  510.                 utils.check_syntax(view)):
  511.                
  512.                 start_thread(view)
  513.    
  514.     def on_selection_modified_async(self, view):
  515.         window = sublime.active_window()
  516.         if view.name() == 'clanglinter_panel':
  517.            
  518.             selected_line, _ = view.rowcol(view.sel()[0].begin())
  519.             if selected_line < len(parser.get_parameters()):
  520.                
  521.                 ui.regions_output_panel(view, selected_line)
  522.                
  523.                 file = parser.get_parameters()[selected_line]['file']
  524.                 line = parser.get_parameters()[selected_line]['line']
  525.                 column = parser.get_parameters()[selected_line]['column']
  526.                
  527.                 window.focus_group(context.get('group'))
  528.                
  529.                 #column = parser.get_true_column(view, line, column)
  530.                
  531.                 flags = "%s:%d:%d" % (file, line, column)
  532.                 window.open_file(flags, sublime.ENCODED_POSITION)
  533.    
  534.     def on_activated_async(self, view):
  535.         if (view.name() != 'clanglinter_panel' and
  536.             view != self.old_view and
  537.             view.file_name()):
  538.            
  539.             self.old_view = view
  540.            
  541.             if (utils.check_extension(os.path.splitext(view.file_name())[1][1:]) and
  542.                 utils.check_syntax(view)):
  543.                
  544.                 if view.is_loading():
  545.                     self.wait_for_loading = True
  546.                 else:
  547.                     start_thread(view)
  548.             else:
  549.                 ui.output_panel_hide()
  550.    
  551.     def on_load_async(self, view):
  552.         if self.wait_for_loading:
  553.             self.wait_for_loading = False
  554.             start_thread(view)
  555.    
  556.     def on_close(self, view):
  557.         if context.get('view') not in sublime.active_window().views():
  558.             ui.output_panel_hide()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement