Skip to content

Commit

Permalink
Merge pull request #13 from hrnr/master
Browse files Browse the repository at this point in the history
Added Error panel.
  • Loading branch information
LuckyGeck committed Jan 31, 2016
2 parents 232c782 + 21c9056 commit 3c835a2
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 0 deletions.
98 changes: 98 additions & 0 deletions Completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
COMPLETION_ERROR_MSG = "[Ycmd][Completion] Error {}"
COMPLETION_NOT_AVAILABLE_MSG = "[Ycmd] No completion available"
ERROR_MESSAGE_TEMPLATE = "[{kind}] {text}"
PANEL_ERROR_MESSAGE_TEMPLATE = "{:<5} {}"
GET_PATH_ERROR_MSG = "[Ycmd][Path] Failed to replace '{}' -> '{}'"
NO_HMAC_MESSAGE = "[Ycmd] You should generate HMAC throug the menu before using plugin"
NOTIFY_ERROR_MSG = "[Ycmd][Notify] Error {}"
Expand Down Expand Up @@ -223,6 +224,9 @@ class YcmdCompletionEventListener(sublime_plugin.EventListener):
view_line = dict()

def on_selection_modified_async(self, view):
if view.id() == ERROR_PANEL.id():
ERROR_PANEL.show_code_for_error()
return
if lang(view) is None or view.is_scratch():
return
self.update_statusbar(view)
Expand Down Expand Up @@ -250,6 +254,11 @@ def on_pre_close(self, view):
if view_id in self.view_cache:
del self.view_cache[view_id]

def on_activated_async(self, view):
if lang(view) is None or view.is_scratch():
return
ERROR_PANEL.update(self.view_cache)

def on_query_completions(self, view, prefix, locations):
'''Sublime Text autocompletion event handler'''
filetype = lang(view)
Expand Down Expand Up @@ -306,6 +315,7 @@ def _on_errors(self, data):
[_ for _ in data
if get_file_path(_['location']['filepath']) == filepath])
self.update_statusbar(active_view(), force=True)
ERROR_PANEL.update(self.view_cache)

def update_statusbar(self, view, force=False):
row, col = get_selected_pos(view)
Expand Down Expand Up @@ -390,3 +400,91 @@ def _completer_cb(self, data, command):
sublime.ENCODED_POSITION)
else:
print_status("[Ycmd][{}]: {}".format(command, jsonResp.get('message', '')))

class YcmdErrorPanelRefresh(sublime_plugin.TextCommand):
def run(self, edit, data):
self.view.erase(edit, sublime.Region(0, self.view.size()))
self.view.insert(edit, 0, data)

class YcmdErrorPanel(object):
# view of this error panel
view = None
# text currently in panel
text = ""
# view with code, for with panel show errors
code_view = None
lines_to_errors = []

def id(self):
if self.view != None:
return self.view.id()
else:
return None

def update_async(self, view_cache, view=None):
t = Thread(None, self.update, 'PanelUpdateAsync', [view_cache, view])
t.daemon = True
t.start()

def update(self, view_cache, view=None):
if view == None:
view = active_view()

messages = []
self.lines_to_errors = []
lines = view_cache.get(view.id(), {})
for line_num, line_regions in sorted(lines.items()):
for region, msg in line_regions.items():
messages.append(PANEL_ERROR_MESSAGE_TEMPLATE.format(str(line_num)+':', msg))
self.lines_to_errors.append(region)
self.text = '\n'.join(messages)
self.code_view = view
if self.is_visible():
self._refresh()

def is_visible(self):
return self.view != None and self.view.window() != None

def _refresh(self):
self.view.set_read_only(False)
self.view.set_scratch(True)
self.view.run_command("ycmd_error_panel_refresh", {"data": self.text})
self.view.set_read_only(True)

def show_code_for_error(self):
if not self.is_visible() or self.code_view == None:
return

# get rid of false positive (non-user interaction)
last_command_name, _, _ = self.view.command_history(0, False)
if last_command_name == 'ycmd_error_panel_refresh':
return

row, _ = get_selected_pos(self.view)
if row < len(self.lines_to_errors):
region = self.lines_to_errors[row]
# we must create sublime region, because cached region is just tuple
sublime_region = sublime.Region(region[0], region[1])
self.code_view.show_at_center(sublime_region)

def open(self):
window = sublime.active_window()
if not self.is_visible():
self.view = window.create_output_panel("clang-errors")
syntax_file = "Packages/YcmdCompletion/ErrorPanel.tmLanguage"
self.view.set_syntax_file(syntax_file)
self._refresh()
window.run_command("show_panel", {"panel": "output.clang-errors"})

def close(self):
sublime.active_window().run_command("hide_panel", {"panel": "output.clang-errors"})

ERROR_PANEL = YcmdErrorPanel()

class YcmdErrorPanelShow(sublime_plugin.WindowCommand):
def run(self):
ERROR_PANEL.open()

class YcmdErrorPanelHide(sublime_plugin.WindowCommand):
def run(self):
ERROR_PANEL.close()
8 changes: 8 additions & 0 deletions Default.sublime-commands
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,13 @@
"caption": "Ycmd: Get Parent For Current Statement",
"command": "ycmd_execute_completer_func",
"args": {"command": "GetParent"}
},
{
"caption": "Ycmd: Show Error Panel",
"command": "ycmd_error_panel_show"
},
{
"caption": "Ycmd: Hide Error Panel",
"command": "ycmd_error_panel_hide"
}
]
34 changes: 34 additions & 0 deletions ErrorPanel.tmLanguage
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>fileTypes</key>
<array>
</array>
<key>name</key>
<string>YcmdErrorPanel</string>
<key>patterns</key>
<array>
<dict>
<key>comment</key>
<string>Warnings</string>
<key>match</key>
<string>^.* \[WARNING\].*$</string>
<key>name</key>
<string>string.quoted.double.c</string>
</dict>
<dict>
<key>comment</key>
<string>Errors</string>
<key>match</key>
<string>^.* \[ERROR\].*$</string>
<key>name</key>
<string>keyword.control.c</string>
</dict>
</array>
<key>scopeName</key>
<string>text.ycmdcompletion</string>
<key>uuid</key>
<string>1a8564ce-f89e-4e0d-8f14-40c5d2a202e5</string>
</dict>
</plist>

0 comments on commit 3c835a2

Please sign in to comment.