diff --git a/Default.sublime-commands b/Default.sublime-commands index 8de9688..568e096 100644 --- a/Default.sublime-commands +++ b/Default.sublime-commands @@ -13,4 +13,4 @@ "command": "todo_review", "args": { "open_files": true } } -] \ No newline at end of file +] diff --git a/Default.sublime-keymap b/Default.sublime-keymap index b9f31f7..25f186f 100644 --- a/Default.sublime-keymap +++ b/Default.sublime-keymap @@ -1,5 +1,4 @@ [ - { "keys": ["down"], "command": "todo_review_results", "context": [ @@ -8,7 +7,6 @@ ], "args": {"direction": "down"} }, - { "keys": ["j"], "command": "todo_review_results", "context": [ @@ -17,7 +15,6 @@ ], "args": {"direction": "down"} }, - { "keys": ["pagedown"], "command": "todo_review_results", "context": [ @@ -26,7 +23,6 @@ ], "args": {"direction": "down_skip"} }, - { "keys": ["up"], "command": "todo_review_results", "context": [ @@ -35,7 +31,6 @@ ], "args": {"direction": "up"} }, - { "keys": ["k"], "command": "todo_review_results", "context": [ @@ -44,7 +39,6 @@ ], "args": {"direction": "up"} }, - { "keys": ["pageup"], "command": "todo_review_results", "context": [ @@ -53,7 +47,6 @@ ], "args": {"direction": "up_skip"} }, - { "keys": ["enter"], "command": "todo_review_results", "context": [ @@ -62,7 +55,6 @@ ], "args": {"open": true} }, - { "keys": ["r"], "command": "todo_review_results", "context": [ @@ -71,5 +63,4 @@ ], "args": {"refresh": true} } - ] diff --git a/Main.sublime-menu b/Main.sublime-menu index 99e57cc..11f70fd 100644 --- a/Main.sublime-menu +++ b/Main.sublime-menu @@ -43,4 +43,4 @@ } ] } -] \ No newline at end of file +] diff --git a/Side Bar.sublime-menu b/Side Bar.sublime-menu index 195dadc..1efc040 100644 --- a/Side Bar.sublime-menu +++ b/Side Bar.sublime-menu @@ -12,4 +12,4 @@ "caption": "-", "id": "side-bar-end-separator" } -] \ No newline at end of file +] diff --git a/TodoReview.hidden-tmLanguage b/TodoReview.hidden-tmLanguage index 8bf867d..7333496 100644 --- a/TodoReview.hidden-tmLanguage +++ b/TodoReview.hidden-tmLanguage @@ -4,71 +4,57 @@ name TodoReview - patterns comment Header - match ^\/\/.*$ - name comment comment Titles - match ^##.*$ - name string comment Line Num - match :[0-9]+\s - name entity.name.function comment Priority - match \(([0-9]{1,2})\) - name variable comment Brackets - match \[(.*?)\] - name entity.name.class comment @tags - match \@\S+ - name keyword - scopeName text.todo-list uuid diff --git a/TodoReview.py b/TodoReview.py index 07bfd11..98b310c 100644 --- a/TodoReview.py +++ b/TodoReview.py @@ -18,36 +18,28 @@ import timeit class Settings(): - def __init__(self, view, args): self.user = sublime.load_settings('TodoReview.sublime-settings') - if not args: self.proj = view.settings().get('todoreview', {}) else: self.proj = args - def get(self, key, default): return self.proj.get(key, self.user.get(key, default)) - class Engine(): - def __init__(self, dirpaths, filepaths, view): self.view = view self.dirpaths = dirpaths self.filepaths = filepaths - if settings.get('case_sensitive', False): case = 0 else: case = re.IGNORECASE - patt_patterns = settings.get('patterns', {}) patt_files = settings.get('exclude_files', []) patt_folders = settings.get('exclude_folders', []) - match_patterns = '|'.join(patt_patterns.values()) match_files = [fnmatch.translate(p) for p in patt_files] match_folders = [fnmatch.translate(p) for p in patt_folders] @@ -56,40 +48,29 @@ def __init__(self, dirpaths, filepaths, view): self.priority = re.compile(r'\(([0-9]{1,2})\)') self.exclude_files = [re.compile(p) for p in match_files] self.exclude_folders = [re.compile(p) for p in match_folders] - self.open = self.view.window().views() self.open_files = [v.file_name() for v in self.open if v.file_name()] - def files(self): seen_paths = [] - for dirpath in self.dirpaths: dirpath = self.resolve(dirpath) for dirp, dirnames, filepaths in os.walk(dirpath, followlinks=True): - if any(p.search(dirp) for p in self.exclude_folders): continue - for filepath in filepaths: self.filepaths.append(os.path.join(dirp, filepath)) - - for filepath in self.filepaths: p = self.resolve(filepath) if p in seen_paths: continue - if any(p.search(filepath) for p in self.exclude_folders): continue - if any(p.search(filepath) for p in self.exclude_files): continue - seen_paths.append(p) yield p - def extract(self, files): encoding = settings.get('encoding', 'utf-8') for p in files: @@ -104,21 +85,16 @@ def extract(self, files): break else: f = io.open(p, 'r', encoding=encoding) - for num, line in enumerate(f, 1): for result in self.patterns.finditer(line): for patt, note in result.groupdict().items(): - if not note and note != '': continue - priority_match = self.priority.search(note) - if(priority_match): priority = int(priority_match.group(1)) else: priority = 100 - yield { 'file': p, 'patt': patt, @@ -126,26 +102,20 @@ def extract(self, files): 'line': num, 'priority': priority } - except(IOError, UnicodeDecodeError): f = None - finally: thread.increment() if f is not None and type(f) is not list: f.close() - def process(self): return self.extract(self.files()) - def resolve(self, directory): return os.path.realpath(os.path.expanduser(os.path.abspath(directory))) - class Thread(threading.Thread): - def __init__(self, engine, callback): self.i = 0; self.engine = engine @@ -153,49 +123,37 @@ def __init__(self, engine, callback): self.lock = threading.RLock() threading.Thread.__init__(self) - def run(self): - self.start = timeit.default_timer() - if sys.version_info < (3,0,0): sublime.set_timeout(self.thread, 1); else: self.thread(); - def thread(self): results = list(self.engine.process()) self.callback(results, self.finish(), self.i) - def finish(self): return round(timeit.default_timer() - self.start, 2) - def increment(self): with self.lock: self.i += 1 sublime.status_message("TodoReview: {0} files scanned".format(self.i)) - class TodoReviewCommand(sublime_plugin.TextCommand): - def run(self, edit, **args): global settings, thread - filepaths = [] self.args = args window = self.view.window() paths = args.get('paths', None) settings = Settings(self.view, args.get('settings', False)) - if not paths and settings.get('include_paths', False): paths = settings.get('include_paths', False) - if args.get('open_files', False): filepaths = [v.file_name() for v in window.views() if v.file_name()] - if not args.get('open_files_only', False): if not paths: paths = window.folders() @@ -205,12 +163,10 @@ def run(self, edit, **args): filepaths.append(p) else: paths = [] - engine = Engine(paths, filepaths, self.view) thread = Thread(engine, self.render) thread.start() - def render(self, results, time, count): self.view.run_command('todo_review_render', { "results": results, @@ -219,9 +175,7 @@ def render(self, results, time, count): "args": self.args }) - class TodoReviewRender(sublime_plugin.TextCommand): - def run(self, edit, results, time, count, args): self.args = args self.edit = edit @@ -230,117 +184,85 @@ def run(self, edit, results, time, count, args): self.results = results self.sorted = self.sort() self.rview = self.get_view() - self.draw_header() self.draw_results() - self.window.focus_view(self.rview) self.args['settings'] = settings.proj self.rview.settings().set('review_args', self.args) - def sort(self): self.largest = 0 - for item in self.results: self.largest = max(len(self.draw_file(item)), self.largest) - self.largest = min(self.largest, settings.get('render_maxspaces', 50)) + 6 - w = settings.get('patterns_weight', {}) key = lambda m: (str(w.get(m['patt'].upper(), m['patt'])), m['priority']) - results = sorted(self.results, key=key) return itertools.groupby(results, key=lambda m: m['patt']) - def get_view(self): self.window = sublime.active_window() - for view in self.window.views(): if view.settings().get('todo_results', False): view.erase(self.edit, sublime.Region(0, view.size())) return view - view = self.window.new_file() view.set_name('TodoReview') view.set_scratch(True) view.settings().set('todo_results', True) - if sys.version_info < (3,0,0): view.set_syntax_file('Packages/TodoReview/TodoReview.hidden-tmLanguage') else: view.assign_syntax('Packages/TodoReview/TodoReview.hidden-tmLanguage') - view.settings().set('line_padding_bottom', 2) view.settings().set('line_padding_top', 2) view.settings().set('word_wrap', False) view.settings().set('command_mode', True) return view - def draw_header(self): - forms = settings.get('render_header_format', '%d - %c files in %t secs') datestr = settings.get('render_header_date', '%A %m/%d/%y at %I:%M%p') - if not forms: forms = '%d - %c files in %t secs' - if not datestr: datestr = '%A %m/%d/%y at %I:%M%p' - if len(forms) == 0: return - date = datetime.datetime.now().strftime(datestr) - res = '// ' res += forms \ .replace('%d', date) \ .replace('%t', str(self.time)) \ .replace('%c', str(self.count)) res += '\n' - self.rview.insert(self.edit, self.rview.size(), res) - def draw_results(self): data = [x[:] for x in [[]] * 2] - for patt, items in self.sorted: items = list(items) - res = '\n## %t (%n)\n' \ .replace('%t', patt.upper()) \ .replace('%n', str(len(items))) - self.rview.insert(self.edit, self.rview.size(), res) - for idx, item in enumerate(items, 1): - line = '%i. %f' \ .replace('%i', str(idx)) \ .replace('%f', self.draw_file(item)) - res = '%f%s%n\n' \ .replace('%f', line) \ .replace('%s', ' '*max((self.largest - len(line)), 1)) \ .replace('%n', item['note']) - start = self.rview.size() self.rview.insert(self.edit, start, res) region = sublime.Region(start, self.rview.size()) - data[0].append(region) data[1].append(item) - self.rview.add_regions('results', data[0], '') - d = dict(('{0},{1}'.format(k.a, k.b), v) for k, v in zip(data[0], data[1])) self.rview.settings().set('review_results', d) - def draw_file(self, item): if settings.get('render_include_folder', False): depth = settings.get('render_folder_depth', 1) @@ -348,77 +270,60 @@ def draw_file(self, item): f = '/'.join(f[-depth:] + [os.path.basename(item['file'])]) else: f = os.path.basename(item['file']) - return '%f:%l' \ .replace('%f', f) \ .replace('%l', str(item['line'])) - class TodoReviewResults(sublime_plugin.TextCommand): - def run(self, edit, **args): self.settings = self.view.settings() - if not self.settings.get('review_results'): return - if args.get('open'): window = self.view.window() index = int(self.settings.get('selected_result', -1)) result = self.view.get_regions('results')[index] - coords = '{0},{1}'.format(result.a, result.b) i = self.settings.get('review_results')[coords] p = "%f:%l".replace('%f', i['file']).replace('%l', str(i['line'])) view = window.open_file(p, sublime.ENCODED_POSITION) window.focus_view(view) return - if args.get('refresh'): args = self.settings.get('review_args') self.view.run_command('todo_review', args) self.settings.erase('selected_result') return - if args.get('direction'): d = args.get('direction') results = self.view.get_regions('results') - if not results: return - start_arr = { 'down': -1, 'up': 0, 'down_skip': -1, 'up_skip': 0 } - dir_arr = { 'down': 1, 'up': -1, 'down_skip': settings.get('navigation_forward_skip', 10), 'up_skip': settings.get('navigation_backward_skip', 10) * -1 } - sel = int(self.settings.get('selected_result', start_arr[d])) sel = sel + dir_arr[d] - if sel == -1: target = results[len(results) - 1] sel = len(results) - 1 - if sel < 0: target = results[0] sel = 0 - if sel >= len(results): target = results[0] sel = 0 - target = results[sel] self.settings.set('selected_result', sel) - region = target.cover(target) self.view.add_regions('selection', [region], 'selected', 'dot') self.view.show(sublime.Region(region.a, region.a + 5)) diff --git a/TodoReview.sublime-settings b/TodoReview.sublime-settings index 7b2ffc8..ccd80da 100644 --- a/TodoReview.sublime-settings +++ b/TodoReview.sublime-settings @@ -17,6 +17,6 @@ "render_maxspaces": 50, "render_header_format": "%d - %c files in %t secs", "render_header_date": "%A %m/%d/%y at %I:%M%p", - "navigation_forward_skip" : 10, - "navigation_backward_skip" : 10 -} \ No newline at end of file + "navigation_forward_skip": 10, + "navigation_backward_skip": 10 +}