Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.8
7 changes: 0 additions & 7 deletions dependencies.json

This file was deleted.

89 changes: 89 additions & 0 deletions settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
from typing import Any, List
import sublime


class TrailingSpacesSettings:
SETTINGS_FILENAME = 'trailing_spaces.sublime-settings'

def __init__(self):
self._settings = sublime.Settings(0)

def load(self) -> None:
self._settings = sublime.load_settings(self.SETTINGS_FILENAME)

def save(self) -> None:
sublime.save_settings(self.SETTINGS_FILENAME)

def _get(self, key: str, value_type: Any) -> Any:
value = self._settings.get(key)
if not isinstance(value, value_type):
raise Exception(f'Invalid value for setting "{key}". Expected "{value_type}", got "{type(value)}')
return value

def _set(self, key: str, value: Any, value_type: Any) -> None:
if not isinstance(value, value_type):
raise Exception(f'Invalid value when setting "{key}". Expected "{value_type}", got "{type(value)}')
self._settings.set(key, value)

# -- Getters and setters for supported options ---------------------------------------------------------------------

@property
def enabled(self) -> bool:
return self._get('enabled', bool)

@property
def file_max_size(self) -> int:
return self._get('file_max_size', int)

@property
def highlight_color(self) -> str:
return self._get('highlight_color', str)

@highlight_color.setter
def highlight_color(self, value: str) -> None:
self._set('highlight_color', value, str)

@property
def include_current_line(self) -> bool:
return self._get('include_current_line', bool)

@property
def include_empty_lines(self) -> bool:
return self._get('include_empty_lines', bool)

@property
def modified_lines_only(self) -> bool:
return self._get('modified_lines_only', bool)

@modified_lines_only.setter
def modified_lines_only(self, value: bool) -> None:
self._set('modified_lines_only', value, bool)

@property
def non_visible_highlighting(self) -> int:
return self._get('non_visible_highlighting', int)

@property
def regexp(self) -> str:
return self._get('regexp', str)

@property
def save_after_trim(self) -> bool:
return self._get('save_after_trim', bool)

@property
def scope_ignore(self) -> List[str]:
return self._get('scope_ignore', list)

@property
def syntax_ignore(self) -> List[str]:
value = self._settings.get('syntax_ignore')
return value if isinstance(value, list) else []

@property
def trim_on_save(self) -> bool:
return self._get('trim_on_save', bool)

@property
def update_interval(self) -> int:
return self._get('update_interval', int)
95 changes: 39 additions & 56 deletions trailing_spaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,53 +8,37 @@
@since: 2011-02-25
'''

import sublime
import sublime_plugin
import difflib
from .settings import TrailingSpacesSettings
from os.path import isfile
import codecs
import difflib
import re

from os.path import isfile
from collections import ChainMap
from sublime_lib import NamedSettingsDict

SETTINGS_FILENAME = 'trailing_spaces.sublime-settings'
# Only need defaults for settings that are not exposed in default settings.
DEFAULT_SETTINGS = {
'syntax_ignore': [],
}
import sublime
import sublime_plugin

# dictionary of currently active view ids and last visible regions
active_views = {}
current_highlight_color = None
current_highlight_color = ''
on_disk = None
# Highlight color as defined in settings. Plugin mutates that setting when disabled so
# that has to be stored.
INITIAL_HIGHLIGHT_COLOR = None
INITIAL_HIGHLIGHT_COLOR = ''
HIGHLIGHT_REGION_KEY = 'TrailingSpacesHighlightedRegions'
settings = None
named_settings = None
settings = TrailingSpacesSettings()


def plugin_loaded():
global settings, named_settings, current_highlight_color, INITIAL_HIGHLIGHT_COLOR

# A settings layer that handles settings with the `trailing_spaces_` prefix (now deprecated).
class DeprecatedSettingsDict(NamedSettingsDict):
def __getitem__(self, key):
return super().__getitem__('trailing_spaces_%s' % key)
global current_highlight_color, INITIAL_HIGHLIGHT_COLOR

deprecated_settings = DeprecatedSettingsDict(SETTINGS_FILENAME)
named_settings = NamedSettingsDict(SETTINGS_FILENAME)
settings = ChainMap(deprecated_settings, named_settings, DEFAULT_SETTINGS)
settings.load()

current_highlight_color = settings['highlight_color']
current_highlight_color = settings.highlight_color
INITIAL_HIGHLIGHT_COLOR = current_highlight_color

if not settings['enabled']:
if not settings.enabled:
current_highlight_color = ""
if settings['highlight_color'] != current_highlight_color:
named_settings.save()
if settings.highlight_color != current_highlight_color:
settings.save()


# Private: Makes sure all timers are stopped.
Expand Down Expand Up @@ -98,16 +82,16 @@ def view_find_all_in_regions(view, regions, regex):
# Returns both the list of regions which map to trailing spaces and the list of
# regions which are to be highlighted, as a list [matched, highlightable].
def find_trailing_spaces(view, scan_only_visible=True):
include_empty_lines = settings['include_empty_lines']
include_current_line = settings['include_current_line']
regexp = settings['regexp'] + "$"
include_empty_lines = settings.include_empty_lines
include_current_line = settings.include_current_line
regexp = settings.regexp + "$"

if not include_empty_lines:
regexp = "(?<=\\S)%s$" % regexp

trailing_regions = []

non_visible_highlighting = settings['non_visible_highlighting']
non_visible_highlighting = settings.non_visible_highlighting

if scan_only_visible:
# find all matches in the currently visible region plus a little before and after
Expand All @@ -120,7 +104,7 @@ def find_trailing_spaces(view, scan_only_visible=True):
else:
trailing_regions = view.find_all(regexp)

ignored_scopes = ",".join(settings['scope_ignore'])
ignored_scopes = ",".join(settings.scope_ignore)
# filter out ignored scopes
trailing_regions = [
region for region in trailing_regions
Expand Down Expand Up @@ -176,7 +160,7 @@ def ignore_view(view):
if not view_syntax or view_settings.get('is_widget'):
return False

for syntax_ignore in settings['syntax_ignore']:
for syntax_ignore in settings.syntax_ignore:
if syntax_ignore in view_syntax:
return True

Expand All @@ -189,7 +173,7 @@ def ignore_view(view):
#
# Returns True or False.
def max_size_exceeded(view):
return view.size() > settings['file_max_size']
return view.size() > settings.file_max_size


# Private: Highlights specified regions as trailing spaces.
Expand Down Expand Up @@ -222,7 +206,7 @@ def toggle_highlighting(view):

# If performing live, highlighted trailing regions must be updated
# internally.
if not settings['enabled']:
if not settings.enabled:
(matched, highlightable) = find_trailing_spaces(view)
highlight_trailing_spaces_regions(view, highlightable)

Expand Down Expand Up @@ -306,7 +290,7 @@ def find_regions_to_delete(view):
(regions, highlightable) = find_trailing_spaces(view, scan_only_visible=False)

# Filtering is required in case triming is restricted to dirty regions only.
if settings['modified_lines_only']:
if settings.modified_lines_only:
modified_lines = get_modified_lines(view)

# If there are no dirty lines, don't do nothing.
Expand Down Expand Up @@ -378,8 +362,8 @@ def run(self):
return

state = toggle_highlighting(view)
named_settings['highlight_color'] = current_highlight_color
named_settings.save()
settings.highlight_color = current_highlight_color
settings.save()
sublime.status_message('Highlighting of trailing spaces is %s' % state)

def is_checked(self):
Expand All @@ -389,47 +373,47 @@ def is_checked(self):
# Public: Toggles "Modified Lines Only" mode on or off.
class ToggleTrailingSpacesModifiedLinesOnlyCommand(sublime_plugin.WindowCommand):
def run(self):
was_on = settings['modified_lines_only']
named_settings['modified_lines_only'] = not was_on
named_settings.save()
was_on = settings.modified_lines_only
settings.modified_lines_only = not was_on
settings.save()

message = "Let's trim trailing spaces everywhere" if was_on \
else "Let's trim trailing spaces only on modified lines"
sublime.status_message(message)

def is_checked(self):
return settings['modified_lines_only']
return settings.modified_lines_only


# Public: Matches and highlights trailing spaces on key events, according to the
# current settings.
class TrailingSpacesListener(sublime_plugin.EventListener):
def on_modified_async(self, view):
if settings['enabled']:
if settings.enabled:
match_trailing_spaces(view)

def on_selection_modified_async(self, view):
if settings['enabled']:
if settings.enabled:
match_trailing_spaces(view)

def on_activated_async(self, view):
if settings['modified_lines_only']:
if settings.modified_lines_only:
self.freeze_last_version(view)

if settings['enabled']:
if settings.enabled:
match_trailing_spaces(view)

# continuously watch view for changes to the visible region
if not view.id() in active_views:
if view.id() not in active_views:
# track
active_views[view.id()] = view.visible_region()
self.update_on_region_change(view)

def on_pre_save(self, view):
if settings['modified_lines_only']:
if settings.modified_lines_only:
self.freeze_last_version(view)

if settings['trim_on_save']:
if settings.trim_on_save:
view.run_command("delete_trailing_spaces")

def on_close(self, view):
Expand All @@ -449,9 +433,8 @@ def update_on_region_change(self, view):
active_views[view.id()] = view.visible_region()

# continue only if the view is still active
if settings['enabled'] and view.id() in active_views:
sublime.set_timeout_async(lambda: self.update_on_region_change(view),
settings['update_interval'])
if settings.enabled and view.id() in active_views:
sublime.set_timeout_async(lambda: self.update_on_region_change(view), settings.update_interval)

# Toggling messes with what is red from the disk, and it breaks the diff
# used when modified_lines_only is true. Honestly, I don't know why (yet).
Expand Down Expand Up @@ -522,7 +505,7 @@ def run(self, edit):
deleted = delete_trailing_regions(self.view, edit)

if deleted:
if settings['save_after_trim'] and not settings['trim_on_save']:
if settings.save_after_trim and not settings.trim_on_save:
sublime.set_timeout(lambda: self.save(self.view), 10)

msg_parts = {"nbRegions": deleted,
Expand Down