feat(SublimeText2.EditorPackages): cache packages
This commit is contained in:
@@ -0,0 +1,195 @@
|
||||
"""Smart folding is a feature borrowed from [Org-mode](http://org-mode.org).
|
||||
|
||||
It enables folding / unfolding the headlines by simply pressing TAB on headlines.
|
||||
|
||||
Global headline folding / unfolding is recommended to be trigged by Shift + TAB,
|
||||
at anywhere.
|
||||
|
||||
"""
|
||||
# Author: Muchenxuan Tong <demon386@gmail.com>
|
||||
|
||||
import re
|
||||
|
||||
import sublime
|
||||
import sublime_plugin
|
||||
|
||||
try:
|
||||
from . import headline
|
||||
from .utilities import is_region_void
|
||||
except ValueError:
|
||||
import headline
|
||||
from utilities import is_region_void
|
||||
|
||||
|
||||
HEADLINE_PATTERN = re.compile(r'^(#+)\s.*')
|
||||
|
||||
|
||||
class SmartFoldingCommand(sublime_plugin.TextCommand):
|
||||
"""Smart folding is used to fold / unfold headline at the point.
|
||||
|
||||
It's designed to bind to TAB key, and if the current line is not
|
||||
a headline, a \t would be inserted.
|
||||
|
||||
"""
|
||||
def run(self, edit):
|
||||
ever_matched = False
|
||||
for region in self.view.sel():
|
||||
matched = self.fold_or_unfold_headline_at_point(region.a)
|
||||
if matched:
|
||||
ever_matched = True
|
||||
if not ever_matched:
|
||||
for r in self.view.sel():
|
||||
self.view.insert(edit, r.a, '\t')
|
||||
self.view.show(r)
|
||||
|
||||
def fold_or_unfold_headline_at_point(self, from_point):
|
||||
"""Smart folding of the current headline.
|
||||
|
||||
Unfold only when it's totally folded. Otherwise fold it.
|
||||
|
||||
"""
|
||||
_, level = headline.headline_and_level_at_point(self.view,
|
||||
from_point)
|
||||
# Not a headline, cancel
|
||||
if level is None or not headline.is_scope_headline(self.view, from_point):
|
||||
return False
|
||||
|
||||
content_region = headline.region_of_content_of_headline_at_point(self.view,
|
||||
from_point)
|
||||
# If the content is empty, Nothing needs to be done.
|
||||
if content_region is None:
|
||||
# Return True because there is a headline anyway.
|
||||
return True
|
||||
|
||||
# Check if content region is folded to decide the action.
|
||||
if self.is_region_totally_folded(content_region):
|
||||
self.unfold_yet_fold_subheads(content_region, level)
|
||||
else:
|
||||
self.view.fold(content_region)
|
||||
return True
|
||||
|
||||
def is_region_totally_folded(self, region):
|
||||
"""Decide if the region is folded. Treat empty region as folded."""
|
||||
if (region is None) or (region.a == region.b):
|
||||
return True
|
||||
|
||||
for i in self.view.folded_regions():
|
||||
if i.contains(region):
|
||||
return True
|
||||
return False
|
||||
|
||||
def unfold_yet_fold_subheads(self, region, level):
|
||||
"""Unfold the region while keeping the subheadlines folded."""
|
||||
## First unfold all
|
||||
self.view.unfold(region)
|
||||
## Fold subheads
|
||||
child_headline_region, _ = headline.find_headline(self.view, region.a, level, True, \
|
||||
headline.MATCH_CHILD)
|
||||
|
||||
while (not is_region_void(child_headline_region) and child_headline_region.b <= region.b):
|
||||
child_content_region = headline.region_of_content_of_headline_at_point(self.view,
|
||||
child_headline_region.a)
|
||||
if child_content_region is not None:
|
||||
self.view.fold(child_content_region)
|
||||
search_start_point = child_content_region.b
|
||||
else:
|
||||
search_start_point = child_headline_region.b
|
||||
|
||||
child_headline_region, _ = headline.find_headline(self.view, \
|
||||
search_start_point, level, True, \
|
||||
headline.MATCH_CHILD,
|
||||
skip_headline_at_point=True)
|
||||
|
||||
|
||||
class GlobalFoldingCommand(SmartFoldingCommand):
|
||||
"""Global folding / unfolding headlines at any point.
|
||||
|
||||
Unfold only when top-level headlines are totally folded.
|
||||
Otherwise fold.
|
||||
|
||||
"""
|
||||
def run(self, edit):
|
||||
if self.is_global_folded():
|
||||
# Unfold all
|
||||
self.unfold_all()
|
||||
else:
|
||||
self.fold_all()
|
||||
|
||||
def is_global_folded(self):
|
||||
"""Check if all headlines are folded.
|
||||
"""
|
||||
region, level = headline.find_headline(self.view, 0, \
|
||||
headline.ANY_LEVEL, True)
|
||||
# Treating no heeadline as folded, since unfolded all makes
|
||||
# no harm in this situation.
|
||||
if is_region_void(region):
|
||||
return True
|
||||
|
||||
point = region.a
|
||||
# point can be zero
|
||||
while (point is not None and region):
|
||||
region = headline.region_of_content_of_headline_at_point(self.view, \
|
||||
point)
|
||||
if not is_region_void(region):
|
||||
point = region.b
|
||||
if not self.is_region_totally_folded(region):
|
||||
return False
|
||||
else:
|
||||
region, level = headline.find_headline(self.view, point, \
|
||||
headline.ANY_LEVEL, \
|
||||
True,
|
||||
skip_headline_at_point=True)
|
||||
if not is_region_void(region):
|
||||
point = region.a
|
||||
return True
|
||||
|
||||
def unfold_all(self):
|
||||
self.view.unfold(sublime.Region(0, self.view.size()))
|
||||
self.view.show(self.view.sel()[0])
|
||||
|
||||
def fold_all(self):
|
||||
region, level = headline.find_headline(self.view, \
|
||||
0, \
|
||||
headline.ANY_LEVEL, \
|
||||
True)
|
||||
|
||||
# At this point, headline region is sure to exist, otherwise it would be
|
||||
# treated as gobal folded. (self.is_global_folded() would return True)
|
||||
point = region.a
|
||||
# point can be zero
|
||||
while (point is not None and region):
|
||||
region = headline.region_of_content_of_headline_at_point(self.view, \
|
||||
point)
|
||||
if not is_region_void(region):
|
||||
point = region.b
|
||||
self.view.fold(region)
|
||||
region, level = headline.find_headline(self.view, point, \
|
||||
headline.ANY_LEVEL,
|
||||
True, \
|
||||
skip_headline_at_point=True)
|
||||
if not is_region_void(region):
|
||||
point = region.a
|
||||
self.adjust_cursors_and_view()
|
||||
|
||||
def adjust_cursors_and_view(self):
|
||||
"""After folder, adjust cursors and view.
|
||||
|
||||
If the current point is inside the folded region, move it move
|
||||
otherwise it's easy to perform some unintentional editing.
|
||||
|
||||
"""
|
||||
folded_regions = self.view.folded_regions()
|
||||
new_sel = []
|
||||
|
||||
for r in self.view.sel():
|
||||
for folded in folded_regions:
|
||||
if folded.contains(r):
|
||||
new_sel.append(sublime.Region(folded.b, folded.b))
|
||||
break
|
||||
else:
|
||||
new_sel.append(r)
|
||||
|
||||
self.view.sel().clear()
|
||||
for r in new_sel:
|
||||
self.view.sel().add(r)
|
||||
self.view.show(r)
|
Reference in New Issue
Block a user