Skip to content
This repository has been archived by the owner on Jan 16, 2025. It is now read-only.

Commit

Permalink
Merged branch newDev into master
Browse files Browse the repository at this point in the history
  • Loading branch information
Allen Ray committed Nov 30, 2016
2 parents 8e5d8af + 6e87b85 commit 8de1d2d
Show file tree
Hide file tree
Showing 4 changed files with 234 additions and 197 deletions.
297 changes: 144 additions & 153 deletions BetterBookmarks.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,30 @@
import collections
import json

global bbFiles
bbFiles = dict([])
# Add our BetterBookmarks cache folder if it doesn't exist
def plugin_loaded():
Marks(True)

def Log(message):
if Settings().get('verbose', False):
print('[BetterBookmarks] ' + message)

def Settings():
return sublime.load_settings('BetterBookmarks.sublime-settings')

class BBFunctions():
@staticmethod
def get_variable(var_string):
return sublime.expand_variables("{:s}".format(var_string), sublime.active_window().extract_variables())
def Variable(var, window=None):
window = window if window else sublime.active_window()
return sublime.expand_variables(var, window.extract_variables())

@staticmethod
def get_current_file_name():
return BBFunctions.get_variable("${file}")

@staticmethod
def get_marks_filename():
directory = "{:s}/User/BetterBookmarks".format(sublime.packages_path())
if not os.path.exists(directory):
os.makedirs(directory)
# Get the path to the cache file.
def Marks(create=False):
directory = '{:s}/User/BetterBookmarks'.format(sublime.packages_path())
if create and not os.path.exists(directory):
os.makedirs(directory)

return "{:s}/{:s}-{:s}.bb_cache".format(directory, BBFunctions.get_variable("${file_base_name}"), BBFunctions.get_variable("${file_extension}"))

@staticmethod
def get_bb_file():
bb = None
filename = BBFunctions.get_current_file_name()

if filename in bbFiles:
bb = bbFiles[filename]
else:
bb = BBFile(sublime.active_window().active_view())
bbFiles[filename] = bb
bb.refresh_bookmarks()

return bb
return Variable(directory + '/${file_base_name}-${file_extension}.bb_cache')

# This class allows the conversion from a sublime.Region to a string (json)
class RegionJSONCoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, sublime.Region):
Expand All @@ -61,159 +48,163 @@ def dict_to_object(d):
d['__type__'] = type
return d

class BBFile():
def __init__(self, view):
self.view = view
self.filename = BBFunctions.get_current_file_name()
self.layers = collections.deque(Settings().get("layer_icons"))
self.layer = Settings().get("default_layer")
class BetterBookmarksCommand(sublime_plugin.TextCommand):
def __init__(self, edit):
sublime_plugin.TextCommand.__init__(self, edit)
self.filename = Variable('${file_name}')
self.layers = collections.deque(Settings().get('layer_icons'))
self.layer = Settings().get('default_layer')
while not self.layers[0] == self.layer:
self.layers.rotate(1)
self.marks = dict([])
for layer in Settings().get("layer_icons"):
self.marks = {}
for layer in Settings().get('layer_icons'):
self.marks[layer] = []
# Unused
# def _should_bookmark(self, layer, line):
# return self._unhash_marks in not self.marks[layer]

def should_bookmark(self, region):
bookmarks = self.view.get_regions("bookmarks")
line = self.view.line(region)

for bookmark in bookmarks:
if line.contains(bookmark):
def _is_empty(self):
for layer in self.layers:
if self.marks[layer]:
return False

return True

def refresh_bookmarks(self):
self.marks[self.layer] = self.view.get_regions("bookmarks")
# Renders the current layers marks to the view
def _render(self):
marks = self._unhash_marks(self.marks[self.layer])
icon = Settings().get('layer_icons')[self.layer]['icon']
scope = Settings().get('layer_icons')[self.layer]['scope']

def add_marks(self, list):
icon = Settings().get("layer_icons")[self.layer]["icon"]
scope = Settings().get("layer_icons")[self.layer]["scope"]
self.view.add_regions('bookmarks', marks, scope, icon, sublime.PERSISTENT | sublime.HIDDEN)

self.view.add_regions("bookmarks", list, scope, icon, sublime.PERSISTENT | sublime.HIDDEN)
# Converts the marks-as-tuples back into sublime.Regions
def _unhash_marks(self, marks):
newMarks = []
for mark in marks:
newMarks.append(sublime.Region(mark[0], mark[1]))

self.refresh_bookmarks()
return newMarks

def load_marks(self):
try:
with open(BBFunctions.get_marks_filename(), 'r') as fp:
self.marks = json.load(fp, object_hook=RegionJSONCoder.dict_to_object)
for tup in self.marks.items():
self.layer = tup[0]
self.add_marks(tup[1])
self.layer = Settings().get("default_layer")
except Exception as e:
pass
# In order to use some list functions, python needs to be able to see a sublime.Region as something simpler;
# in this case a tuple.
def _hash_marks(self, marks):
newMarks = []
for mark in marks:
newMarks.append((mark.a, mark.b))

def save_marks(self):
with open(BBFunctions.get_marks_filename(), 'w') as fp:
json.dump(self.marks, fp, cls=RegionJSONCoder)
return newMarks

def add_mark(self, line, layer=None):
newMarks = []
markFound = False
# Internal function for adding a list of marks to the existing ones.
# Any marks that exist in both lists will be removed as this case is when the user is
# attempting to remove a mark.
def _add_marks(self, newMarks, layer=None):
layer = layer if layer else self.layer
marks = []

if not layer:
layer = self.layer
elif not layer == self.layer:
print("Cache current layer and load layer from file")
if newMarks:
newMarks = self._hash_marks(newMarks)

if not layer in self.marks:
self.marks[layer] = []
if not layer in self.marks:
self.marks[layer] = []

marks = self.marks[layer]
marks = self.marks[layer]

for mark in marks:
if line.contains(mark):
markFound = True
else:
newMarks.append(mark)
for mark in newMarks:
if mark in marks:
marks.remove(mark)
else:
marks.append(mark)

if not markFound:
newMarks.append(line)
self.marks[layer] = marks

self.add_marks(newMarks)
if layer is self.layer:
self._render()

def change_to_layer(self, layer):
# Changes the layer to the given one and updates any and all of the status indicators.
def _change_to_layer(self, layer):
self.layer = layer
sublime.status_message(self.layer)
status_name = 'bb_layer_status'

if self.layer in self.marks:
self.add_marks(self.marks[self.layer])
else:
self.marks[self.layer] = []
status = Settings().get('layer_status_location', ['permanent'])

def swap_layer(self, direction):
if direction == "prev":
self.layers.rotate(-1)
elif direction == "next":
self.layers.rotate(1)
if 'temporary' in status:
sublime.status_message(self.layer)
if 'permanent' in status:
self.view.set_status(status_name, 'Bookmark Layer: {:s}'.format(self.layer))
else:
sublime.error_message("Invalid layer swap direction.")

self.change_to_layer(self.layers[0])
self.view.erase_status(status_name)
if 'popup' in status:
if self.view.is_popup_visible():
self.view.update_popup(self.layer)
else:
self.view.show_popup(self.layer, 0, -1, 1000, 1000, None, None)

class BetterBookmarksMarkLineCommand(sublime_plugin.TextCommand):
def run(self, edit):
bb = BBFunctions.get_bb_file()
bb.add_mark(self.view.line(self.view.sel()[0]))
self._render()

class BetterBookmarksClearMarksCommand(sublime_plugin.TextCommand):
def run(self, edit):
bb = BBFunctions.get_bb_file()
bb.add_marks([])
def run(self, edit, **args):
view = self.view
subcommand = args['subcommand']

if subcommand == 'mark_line':
line = args['line'] if 'line' in args else view.sel()[0]
layer = args['layer'] if 'layer' in args else self.layer

self._add_marks([line], layer)
elif subcommand == 'clear_marks':
layer = args['layer'] if 'layer' in args else self.layer
self._add_marks([], layer)
elif subcommand == 'clear_all':
for layer in self.layers:
self._add_marks([], layer)
elif subcommand == 'layer_swap':
direction = args.get('direction')
if direction == 'prev':
self.layers.rotate(-1)
elif direction == 'next':
self.layers.rotate(1)
else:
sublime.error_message('Invalid layer swap direction.')

self._change_to_layer(self.layers[0])
elif subcommand == 'on_load':
Log('Loading BBFile for ' + self.filename)
try:
with open(Marks(), 'r') as fp:
marks = json.load(fp, object_hook=RegionJSONCoder.dict_to_object)
for layer, regions in marks.items():
self.marks[layer] = regions
except Exception as e:
pass
self._change_to_layer(Settings().get('default_layer'))
elif subcommand == 'on_save':
if not self._is_empty():
Log('Saving BBFile for ' + self.filename)
with open(Marks(), 'w') as fp:
json.dump(self.marks, fp, cls=RegionJSONCoder)
elif subcommand == 'on_close':
if self._is_empty():
Log('Removing BBFile for ' + self.filename)
try:
os.remove(Marks())
except FileNotFoundError as e:
pass

class BetterBookmarksClearAllMarksCommand(sublime_plugin.TextCommand):
def run(self, edit):
bb = BBFunctions.get_bb_file()
blayer = bb.layer
for layer in bb.layers:
bb.layer = layer
bb.add_marks([])
class BetterBookmarksEventListener(sublime_plugin.EventListener):
def __init__(self):
sublime_plugin.EventListener.__init__(self)

bb.layer = blayer
def _contact(self, view, subcommand):
view.run_command('better_bookmarks', {'subcommand': subcommand})

class BetterBookmarksSwapLayerCommand(sublime_plugin.TextCommand):
def run(self, edit, **args):
bb = BBFunctions.get_bb_file()
bb.swap_layer(args.get("direction"))
def on_load_async(self, view):
if Settings().get('load_marks_on_load'):
self._contact(view, 'on_load')

class BetterBookmarksEventListener(sublime_plugin.EventListener):
def on_load(self, view):
if Settings().get("load_marks_on_load"):
filename = BBFunctions.get_current_file_name()
if not filename in bbFiles:
print("[BetterBookmarksEventListener] Creating BBFile for " + filename)
bb = BBFile(view)
bb.load_marks()
bbFiles[filename] = bb

def on_pre_save(self, view):
if Settings().get("auto_save_marks"):
filename = BBFunctions.get_current_file_name()

bb = BBFunctions.get_bb_file()

if bb.marks.keys():
bb.save_marks()

def on_post_save(self, view):
if BBFunctions.get_variable("${file_name}") == "BetterBookmarks.sublime-settings":
for bb in bbFiles.items():
bb[1].layers.clear()
bb[1].layers.extend(Settings().get("layer_icons"))
def on_pre_save_async(self, view):
if Settings().get('auto_save_marks'):
self._contact(view, 'on_save')

def on_pre_close(self, view):
if Settings().get("cleanup_empty_cache_on_close"):
filename = BBFunctions.get_current_file_name()
bb = BBFunctions.get_bb_file()
empty = True
for item in bb.marks.items():
empty = empty and not item[1]
if bb.marks.items() and empty:
try:
os.remove(BBFunctions.get_marks_filename())
except FileNotFoundError as e:
pass
if filename in bbFiles:
del bbFiles[filename]
if Settings().get('cleanup_empty_cache_on_close'):
self._contact(view, 'on_close')
7 changes: 4 additions & 3 deletions BetterBookmarks.sublime-settings
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
{
"automark_functions": false,
"verbose": true,
"auto_save_marks": true,
"load_marks_on_load": true,
"cleanup_empty_cache_on_close": true,
"layer_icons": {
"bookmarks": {"icon": "bookmark", "scope": "string"},
"functions": {"icon": "Packages/BetterBookmarks/icons/function.png", "scope": "comment"},
"todos": {"icon": "Packages/BetterBookmarks/icons/todo.png", "scope": "comment"},
"functions": {"icon": "Packages/Better Bookmarks/icons/function.png", "scope": "comment"},
"todos": {"icon": "Packages/Better Bookmarks/icons/todo.png", "scope": "comment"},
},
"default_layer": "bookmarks",
"layer_status_location": ["permanent"]
}
Loading

0 comments on commit 8de1d2d

Please sign in to comment.