Skip to content

Commit

Permalink
Display activity indicator while rebuilding tags
Browse files Browse the repository at this point in the history
  • Loading branch information
deathaxe committed Jan 12, 2024
1 parent 03c0d17 commit 9f7d84e
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 40 deletions.
123 changes: 123 additions & 0 deletions plugins/activity_indicator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import sublime
from threading import RLock


class ActivityIndicator:
"""
An animated text-based indicator to show that some activity is in progress.
The `target` argument should be a :class:`sublime.View` or :class:`sublime.Window`.
The indicator will be shown in the status bar of that view or window.
If `label` is provided, then it will be shown next to the animation.
:class:`ActivityIndicator` can be used as a context manager.
"""

def __init__(self, label=None):
self.label = label
self.interval = 120
self._lock = RLock()
self._running = False
self._ticks = 0
self._view = None

def __enter__(self):
self.start()
return self

def __exit__(self, exc_type, exc_value, traceback):
self.stop()

def clear(self):
if self._view:
self._view.erase_status("_ctags_activity")
self._view = None

def start(self):
"""
Start displaying the indicator and animate it.
:raise RuntimeError: if the indicator is already running.
"""

with self._lock:
if self._running:
raise RuntimeError("Timer is already running")
self._running = True
self._ticks = 0
self.update(self.render_indicator_text())
sublime.set_timeout(self.tick, self.interval)

def stop(self):
"""
Stop displaying the indicator.
If the indicator is not running, do nothing.
"""

with self._lock:
if self._running:
self._running = False
self.clear()

def finish(self, message):
"""
Stop the indicator and display a final status message
:param message:
The final status message to display
"""

def clear():
with self._lock:
self.clear()

if self._running:
with self._lock:
self._running = False
self.update(message)

sublime.set_timeout(clear, 4000)

def tick(self):
"""
Invoke status bar update with specified interval.
"""

if self._running:
self._ticks += 1
self.update(self.render_indicator_text())
sublime.set_timeout(self.tick, self.interval)

def update(self, text):
"""
Update activity indicator and label in status bar.
:param text:
The text to display in the status bar
"""

view = sublime.active_window().active_view()
if view and view != self._view:
if self._view:
self._view.erase_status("_ctags_activity")
self._view = view
if self._view:
self._view.set_status("_ctags_activity", text)

def render_indicator_text(self):
"""
Render activity indicator and label.
:returns:
The activity indicator string to display in the status bar
"""

text = "⣷⣯⣟⡿⢿⣻⣽⣾"[self._ticks % 8]
if self.label:
text += " " + self.label
return text

def set_label(self, label):
with self._lock:
self.label = label
76 changes: 36 additions & 40 deletions plugins/cmds.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import sublime_plugin
from sublime import status_message, error_message

from .activity_indicator import ActivityIndicator

from .ctags import (
FILENAME,
PATH_ORDER,
Expand Down Expand Up @@ -822,49 +824,43 @@ def build_ctags(self, paths, command, tag_file, recursive, opts):
:returns: None
"""
with ActivityIndicator("CTags: Rebuilding tags...") as progress:
for i, path in enumerate(paths, start=1):
if len(paths) > 1:
progress.update(
"CTags: Rebuilding tags [%d/%d]..." % (i, len(paths))
)

def tags_building(tag_file):
"""Display 'Building CTags' message in all views"""
print(("Building CTags for %s: Please be patient" % tag_file))
in_main(
lambda: status_message(
"Building CTags for {0}: Please be" " patient".format(tag_file)
)
)()

def tags_built(tag_file):
"""Display 'Finished Building CTags' message in all views"""
print(("Finished building %s" % tag_file))
in_main(lambda: status_message("Finished building {0}".format(tag_file)))()
in_main(lambda: tags_cache[os.path.dirname(tag_file)].clear())()

for path in paths:
tags_building(path)

try:
result = build_ctags(
path=path,
tag_file=tag_file,
recursive=recursive,
opts=opts,
cmd=command,
)
except IOError as e:
error_message(e.strerror)
return
except subprocess.CalledProcessError as e:
if sublime.platform() == "windows":
str_err = " ".join(e.output.decode("windows-1252").splitlines())
else:
str_err = e.output.decode(locale.getpreferredencoding()).rstrip()
try:
result = build_ctags(
path=path,
tag_file=tag_file,
recursive=recursive,
opts=opts,
cmd=command,
)
except IOError as e:
error_message(e.strerror)
return
except subprocess.CalledProcessError as e:
if sublime.platform() == "windows":
str_err = " ".join(e.output.decode("windows-1252").splitlines())
else:
str_err = e.output.decode(
locale.getpreferredencoding()
).rstrip()

error_message(str_err)
return
except Exception as e:
error_message(
"An unknown error occured.\nCheck the console for info."
)
raise e

error_message(str_err)
return
except Exception as e:
error_message("An unknown error occured.\nCheck the console for info.")
raise e
in_main(lambda: tags_cache[os.path.dirname(result)].clear())()

tags_built(result)
progress.finish("Finished building tags!")

if tag_file in ctags_completions:
del ctags_completions[tag_file] # clear the cached ctags list
Expand Down

0 comments on commit 9f7d84e

Please sign in to comment.