Skip to content

Commit

Permalink
Add "go to next/previous error" commands.
Browse files Browse the repository at this point in the history
Inspired by SublimeClang.
  • Loading branch information
nh2 committed Feb 20, 2013
1 parent 45ed906 commit 83860cf
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 1 deletion.
8 changes: 8 additions & 0 deletions Default.sublime-commands
Expand Up @@ -84,5 +84,13 @@
{
"caption": "SublimeHaskell: Reinspect all",
"command": "sublime_haskell_reinspect_all"
},
{
"caption": "SublimeHaskell: Go to next error",
"command": "sublime_haskell_next_error"
},
{
"caption": "SublimeHaskell: Go to previous error",
"command": "sublime_haskell_previous_error"
}
]
11 changes: 11 additions & 0 deletions Default.sublime-keymap
Expand Up @@ -13,5 +13,16 @@
"args": {"characters": "("},
"keys": ["("],
"context": [ { "key": "is_haskell_source" }, { "key": "auto_completion_popup" } ]
},
// Same keybindings as SublimeClang
{
"command": "sublime_haskell_next_error",
"keys": ["alt+d", "alt+e"],
"context": [ { "key": "is_haskell_source" } ]
},
{
"command": "sublime_haskell_previous_error",
"keys": ["alt+shift+d", "alt+shift+e"],
"context": [ { "key": "is_haskell_source" } ]
}
]
5 changes: 4 additions & 1 deletion ghcmod.py
Expand Up @@ -4,7 +4,7 @@
from threading import Thread

from sublime_haskell_common import log, is_enabled_haskell_command, get_haskell_command_window_view_file_project, call_ghcmod_and_wait
from parseoutput import parse_output_messages, show_output_result_text, format_output_messages, mark_messages_in_views, hide_output
from parseoutput import parse_output_messages, show_output_result_text, format_output_messages, mark_messages_in_views, hide_output, set_global_error_messages


def lint_as_hints(msgs):
Expand Down Expand Up @@ -118,6 +118,9 @@ def wait_ghcmod_and_parse(view, filename, msg, cmds_with_args, alter_messages_cb
for p in parsed:
parsed_messages.append((cmd, p))

# Set global error list
set_global_error_messages(parsed)

if alter_messages_cb:
alter_messages_cb(parsed_messages)

Expand Down
71 changes: 71 additions & 0 deletions parseoutput.py
@@ -1,8 +1,10 @@
import os
import re
import sublime
import sublime_plugin
import time
from threading import Thread
from collections import defaultdict

from sublime_haskell_common import log, are_paths_equal, call_and_wait, get_setting_async

Expand All @@ -20,6 +22,12 @@
result_file_regex = r'^(\S*?): line (\d+), column (\d+):$'


# Global list of errors. Used e.g. for jumping to the next one.
# Properly assigned being a defaultdict in clear_error_marks().
# Structure: ERRORS[filename][m.line] = OutputMessage()
ERRORS = {}


def filename_of_path(p):
"""Returns everything after the last slash or backslash."""
# Not using os.path here because we don't know/care here if
Expand Down Expand Up @@ -61,6 +69,22 @@ def find_region_in_view(self, view):
return region


def clear_error_marks():
global ERRORS

listdict = lambda: defaultdict(list)
ERRORS = defaultdict(listdict)


def set_global_error_messages(messages):
global ERRORS

clear_error_marks()

for m in messages:
ERRORS[m.filename][m.line].append(m)


def run_build_thread(view, cabal_project_dir, msg, cmd, on_done):
run_chain_build_thread(view, cabal_project_dir, msg, [cmd], on_done)

Expand Down Expand Up @@ -133,6 +157,9 @@ def parse_output_messages_and_show(view, msg, base_dir, exit_code, stderr):
# The unparseable part (for other errors)
unparsable = output_regex.sub('', stderr).strip()

# Set global error list
set_global_error_messages(parsed_messages)

# If we couldn't parse any messages, just show the stderr
# Otherwise the parsed errors and the unparsable stderr remainder
outputs = []
Expand Down Expand Up @@ -183,6 +210,50 @@ def mark_messages_in_views(errors):
}


# These next and previous commands were shamelessly copied
# from the great SublimeClang plugin.

class SublimeHaskellNextError(sublime_plugin.TextCommand):
def run(self, edit):
print "SublimeHaskellNextError"
v = self.view
fn = v.file_name().encode("utf-8")
line, column = v.rowcol(v.sel()[0].a)
gotoline = -1
if fn in ERRORS:
for errLine in ERRORS[fn]:
if errLine > line:
gotoline = errLine
break
# No next line: Wrap around if possible
if gotoline == -1 and len(ERRORS[fn]) > 0:
gotoline = ERRORS[fn].keys()[0]
if gotoline != -1:
v.window().open_file("%s:%d" % (fn, gotoline), sublime.ENCODED_POSITION)
else:
sublime.status_message("No more errors or warnings!")


class SublimeHaskellPreviousError(sublime_plugin.TextCommand):
def run(self, edit):
v = self.view
fn = v.file_name().encode("utf-8")
line, column = v.rowcol(v.sel()[0].a)
gotoline = -1
if fn in ERRORS:
for errLine in ERRORS[fn]:
if errLine < line:
gotoline = errLine
# No previous line: Wrap around if possible
if gotoline == -1 and len(ERRORS[fn]) > 0:
gotoline = ERRORS[fn].keys()[-1]
if gotoline != -1:
v.window().open_file("%s:%d" % (fn, gotoline), sublime.ENCODED_POSITION)
else:
sublime.status_message("No more errors or warnings!")



def region_key(name):
return 'subhs-{0}s'.format(name)

Expand Down

0 comments on commit 83860cf

Please sign in to comment.