import sublime import sublime_plugin import re class CycleCommentsCommand(sublime_plugin.TextCommand): def run(self, edit): view = self.view syntax_path = view.settings().get("syntax") if not syntax_path: return syntax_name = syntax_path.split("/")[-1] \ .replace(".sublime-syntax", "") \ .replace(".tmLanguage", "") settings = sublime.load_settings("commentcycle.sublime-settings") comment_styles = settings.get(syntax_name) if not comment_styles: sublime.status_message("No comment styles for {}".format(syntax_name)) return # Match longest prefix first (## before #) comment_styles = sorted(comment_styles, key=lambda x: len(x[0]), reverse=True) for region in list(view.sel()): if region.empty(): region = view.line(region) original = view.substr(region) indent_match = re.match(r'^(\s*)', original) indent = indent_match.group(1) content = original[len(indent):] stripped = content.strip() state = 0 for i, pair in enumerate(comment_styles): start, end = pair if stripped.startswith(start): if not end or stripped.endswith(end): state = i + 1 break next_state = (state + 1) % (len(comment_styles) + 1) # Remove current comment if state > 0: start, end = comment_styles[state - 1] stripped = stripped[len(start):].lstrip() if end: stripped = stripped[:-len(end)].rstrip() # Apply next comment if next_state > 0: start, end = comment_styles[next_state - 1] if end: stripped = "{} {} {}".format(start, stripped, end) else: stripped = "{} {}".format(start, stripped) new_line = indent + stripped view.replace(edit, region, new_line)