Skip to content

Commit fee473e

Browse files
committed
Plugins: Update set unsaved view name listener
This commit implements auto view name assignment according to ST's default implementation but instead of sticking with first line only, it still prefers first heading if available.
1 parent 887e298 commit fee473e

File tree

4 files changed

+93
-7
lines changed

4 files changed

+93
-7
lines changed

plugins/decorators.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import sublime
2+
3+
from functools import partial, wraps
4+
from time import time as now
5+
6+
7+
def debounced(delay_in_ms, sync=False):
8+
"""Delay calls to event hooks until they weren't triggered for n ms.
9+
10+
Performs view-specific tracking and is best suited for the
11+
`on_modified` and `on_selection_modified` methods
12+
and their `_async` variants.
13+
The `view` is taken from the first argument for `EventListener`s
14+
and from the instance for `ViewEventListener`s.
15+
16+
Calls are only made when the `view` is still "valid" according to ST's API,
17+
so it's not necessary to check it in the wrapped function.
18+
"""
19+
20+
# We assume that locking is not necessary because each function will be called
21+
# from either the ui or the async thread only.
22+
set_timeout = sublime.set_timeout if sync else sublime.set_timeout_async
23+
24+
def decorator(func):
25+
call_at = {}
26+
27+
def _debounced_callback(view, callback):
28+
if not view.is_valid():
29+
del call_at[view.view_id]
30+
return
31+
diff = call_at[view.view_id] - now() * 1000
32+
if diff > 0:
33+
set_timeout(partial(_debounced_callback, view, callback), diff)
34+
else:
35+
del call_at[view.view_id]
36+
callback()
37+
38+
@wraps(func)
39+
def wrapper(self, *args, **kwargs):
40+
view = self.view if hasattr(self, 'view') else args[0]
41+
pending = view.view_id in call_at
42+
call_at[view.view_id] = now() * 1000 + delay_in_ms
43+
if pending:
44+
return
45+
callback = partial(func, self, *args, **kwargs)
46+
set_timeout(partial(_debounced_callback, view, callback), delay_in_ms)
47+
48+
return wrapper
49+
50+
return decorator

plugins/headings/common.py

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import re
2+
import unicodedata
3+
24
import sublime
35

6+
from ..decorators import debounced
47
from ..view import MdeViewEventListener
58

69
HEADINGS_RE = re.compile(
@@ -54,15 +57,42 @@ class MdeUnsavedViewNameSetter(MdeViewEventListener):
5457
This view event listener prints the first heading as tab title of unsaved documents.
5558
"""
5659

57-
MAX_NAME = 50
58-
60+
@debounced(50, sync=True)
5961
def on_modified(self):
60-
if self.view.file_name() is not None or not self.view.settings().get(
61-
"set_unsaved_view_name", True
62-
):
62+
if self.view.file_name() or self.view.is_loading():
63+
return
64+
65+
view_settings = self.view.settings()
66+
if not view_settings.get('set_unsaved_view_name', True):
67+
return
68+
69+
cur_name = view_settings.get('mde_auto_name')
70+
view_name = self.view.name()
71+
72+
# Name has been explicitly set, don't override it
73+
if not cur_name and view_name:
74+
return
75+
76+
# Name has been explicitly changed, don't override it
77+
if cur_name and cur_name != view_name:
78+
view_settings.erase('mde_auto_name')
79+
return
80+
81+
# Don't set the names on widgets, it'll just trigger spurious
82+
# on_modified callbacks
83+
if view_settings.get('is_widget'):
6384
return
6485

6586
name = first_heading_text(self.view)
66-
if len(name) > self.MAX_NAME:
67-
name = name[: self.MAX_NAME] + "…"
87+
if len(name) > 50:
88+
name = name[: 50] + "…"
89+
90+
# Filter non-printable characters. Without this the save dialog on
91+
# windows fails to open.
92+
first_line = ''.join(c for c in name if unicodedata.category(c)[0] != 'C')
93+
6894
self.view.set_name(name)
95+
view_settings.set('mde_auto_name', name)
96+
97+
# make sure ST's default auto-namer keeps quite
98+
view_settings.erase('auto_name')

syntaxes/Markdown.sublime-settings

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
{
2+
// Disable ST's default view name assigner
3+
"set_unsaved_view_name_for_syntax": false,
4+
25
"trim_trailing_white_space_on_save": "none"
36
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
{
2+
// Disable ST's default view name assigner
3+
"set_unsaved_view_name_for_syntax": false,
4+
25
"trim_trailing_white_space_on_save": "none"
36
}

0 commit comments

Comments
 (0)