Skip to content

Commit

Permalink
Refactor highlighter
Browse files Browse the repository at this point in the history
Add style setting
Show different highlights for different scopes
Use last selection for multiple selections
  • Loading branch information
kapitanluffy committed Nov 4, 2019
1 parent 2523c20 commit 4b4606d
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 67 deletions.
20 changes: 10 additions & 10 deletions SemanticHighlighter.py
@@ -1,33 +1,33 @@
import imp
import sys

import sublime
import sublime_plugin

from .src.state import *
from .src.commands import *
from .src.listeners import *
from .src import *

def plugin_loaded():
print("Semantic Highlighter loaded")
global settings, syntax_scopes

settings = sublime.load_settings('SemanticHighlighter.sublime-settings')

settings.clear_on_change('scopes')
settings.add_on_change('scopes', plugin_loaded)

if (settings.has('scopes')):
syntax_scopes = settings.get('scopes', {})
settings.clear_on_change('style')
settings.add_on_change('style', plugin_loaded)

def plugin_unloaded():
print("semantic highlighter unloaded")
state['style'] = styles[settings.get('style', 'underline')]
state['syntax_scopes'] = settings.get('scopes', {})

class SemanticHighlighterDebugCommand(sublime_plugin.TextCommand):
def run(self, edit):
print("debug")
analyzer = ScopeAnalyzer();
selection = self.view.sel()
analyzer.guess_block(self.view, selection[0])
analyzer.analyze(self.view, selection[0])

class SemanticHighlighterMarkCommand(sublime_plugin.TextCommand):
def run(self, edit):
print("keyboard")
self.view.run_command('semantic_highlighter_highlight', { "locked": True })

1 change: 1 addition & 0 deletions SemanticHighlighter.sublime-settings
@@ -1,4 +1,5 @@
{
"style": "underline",
"scopes": {
"base": [
"variable.other",
Expand Down
6 changes: 6 additions & 0 deletions src/__init__.py
@@ -0,0 +1,6 @@

from .state import *
from .helpers import *
from .commands.highlight import *
from .commands.toggle import *
from .listeners.view_event import *
159 changes: 110 additions & 49 deletions src/commands/highlight.py
Expand Up @@ -12,97 +12,135 @@
class SemanticHighlighterHighlightCommand(sublime_plugin.TextCommand):
scopes = []
locked = False
highlighted = None
highlighted = {}
locked_highlighted = {}
style = None
key = None
state = {}
key = 'plugin.semantic_highlighter'
state = None
symbols = {}
scope_analyzer = None
current_selection = set()

def run(self, edit, **kwargs):
self.locked = kwargs.get('locked')

def get_scopes(self):
syntax = get_syntax(self.view)
scopes = get_scopes(syntax)
self.scopes = ",".join(scopes)
self.key = 'plugin.semantic_highlighter'
return ",".join(scopes)

def get_words(self, selection):
words = set()

for region in selection:
# ignore text selections
if (region.size() > 0):
continue

word = self.get_word(region)
words.add(word)

return words

def run(self, edit, **kwargs):
global state
self.locked = kwargs.get('locked')
self.scopes = self.get_scopes()
self.style = state['style']

styles = {
'outline': sublime.DRAW_NO_FILL,
'fill': sublime.DRAW_NO_OUTLINE,
'underline': sublime.DRAW_NO_FILL | sublime.DRAW_NO_OUTLINE | sublime.DRAW_SOLID_UNDERLINE
}
self.style = styles['underline']
if self.state == None:
self.state = state

# only use last selection region
selection = self.view.sel()
selection = [selection[-1]]

# words = self.get_words(selection)
# current_highlighted_words = set(self.state['current_highlight'].keys())

# if current_highlighted_words == words:
# print(current_highlighted_words, words)
# return False

point = kwargs.get('point')
if (point != None):
selection.clear()
selection.add(point)

self.scope_analyzer = ScopeAnalyzer()
# words = set()

for region in selection:
# ignore text selections
if (region.size() > 0):
continue

highlighted = self.handle_region(region)
target_word = self.get_word(region)
highlights = self.handle_region(target_word)

if (highlighted == False):
if (highlights == False):
continue

# if (self.locked == True):
# self.locked_highlighted[highlighted['word']] = highlighted
# self.locked_highlighted[highlights['word']] = highlights
# continue

# highlighted.highlight(lock)
# highlighted.unhighlight()
# self.current_selection.add(target_word)
self.state['current_highlight'][target_word] = highlights

for k,h in highlights.items():
self.highlight(h['key'], h['regions'], h['color'])

self.highlighted = highlighted
self.state['current_highlight'] = highlighted

return True

def handle_region(self, region):
color = randrange(0, 144)
target = self.get_word(region)
key = self.key
def handle_region(self, target):
# skip if target is in the highlighted
if (target in self.state['current_highlight'] and self.locked != True):
return False

# clear higlighted regions
self.unhighlight(target)

# skip if not a valid "word", clear highlight if exists
if (target == False):
if (self.highlighted != None):
self.unhighlight(self.highlighted)
self.highlighted = None
return False

# skip if target is equal to the highlighted
if (self.highlighted != None):
if (target == self.highlighted['word'] and self.locked != True):
return False
# if (self.locked == True):
# key = "%s.%s" % (key, target)

key = self.key
regions = self.get_target_instances(target)
highlights = {}
symbol_regions = {}
symbols = {}

for r in regions:
region_scope = self.scope_analyzer.analyze(self.view, r)
region_scope_name = "Global"
region_scope_region = self.view.substr(self.view.line(r))

if (self.locked == True):
key = "%s.%s" % (key, target)
if (region_scope != None):
region_scope_region = self.view.substr(self.view.line(region_scope))
region_scope_name = self.view.substr(self.view.word(region_scope))

instances = self.get_target_instances(target)
regions = [region] + instances
symbol_key = "%s.%s.%s" % (key, region_scope_name, target)

# for r in regions:
# region_scope = self.scope_analyzer.analyze(self.view, region)
# region_scope_name = self.view.substr(self.view.word(region_scope))
# symbol_key = "%s.%s" % (region_scope_name, target)
if symbol_key in symbols:
color = symbols[symbol_key]

# if symbol_key in self.symbols:
# color = self.symbols[symbols]
if symbol_key not in symbols:
color = randrange(0, 144)
symbols[symbol_key] = color

# if symbol_key in self.symbols == False:
# self.symbols[symbols] = color
if symbol_key in symbol_regions:
symbol_regions[symbol_key].append(r)

self.highlight(key, regions, color)
highlighted = { "word": target, "key": key, "color": color, "locked": self.locked, "active": True, "regions": regions }
if symbol_key not in symbol_regions:
symbol_regions[symbol_key] = []
symbol_regions[symbol_key].append(r)

return highlighted
# print(r, "%s -> %s [%s]" % (region_scope_name, target, region_scope_region))
highlights[symbol_key] = { "word": target, "key": symbol_key, "color": color, "locked": self.locked, "active": True, "regions": symbol_regions[symbol_key] }

return highlights

def get_target_instances(self, target):
instances = self.view.find_all(target, sublime.LITERAL)
Expand Down Expand Up @@ -139,8 +177,31 @@ def is_scope_match(self, point, scopes):
midpoint = (point.a + point.b) / 2
return self.view.match_selector(midpoint, scopes)

def unhighlight(self, word):
self.view.erase_regions(word['key'])
def unhighlight(self, target):
deletables = set()

# highlight_keys = list(self.state['current_highlight'])
# for k in highlight_keys:
# if target == k:
# continue

# highlights = self.state['current_highlight'].pop(k)

# for wk,highlight in highlights.items():
# self.view.erase_regions(highlight['key'])

for word,highlights in self.state['current_highlight'].items():
if target == word:
continue
deletables.add(word)

for key in highlights:
highlight = highlights[key]
# self.current_selection.remove(highlight['word'])
self.view.erase_regions(highlight['key'])

for word in deletables:
del self.state['current_highlight'][word]

def highlight(self, key, regions, color):
self.view.add_regions(key, regions, 'plugin.semantic_highlighter.color' + str(color) , '', self.style)
Expand Down
2 changes: 1 addition & 1 deletion src/commands/toggle.py
Expand Up @@ -4,7 +4,7 @@
from ..state import *
from ..helpers import *

class SemanticHighlightToggleCommand(sublime_plugin.TextCommand):
class SemanticHighlighterToggleCommand(sublime_plugin.TextCommand):
def run(self, edit):
global highlight_enabled
highlight_enabled = not highlight_enabled
Expand Down
2 changes: 1 addition & 1 deletion src/helpers.py
Expand Up @@ -12,7 +12,7 @@ def get_syntax(view):
return syntax

def get_scopes(syntax):
return syntax_scopes.get('base', []) + syntax_scopes.get(syntax, [])
return state['syntax_scopes'].get('base', []) + state['syntax_scopes'].get(syntax, [])

def get_region_string(region, line = False):
v = sublime.active_window().active_view()
Expand Down
8 changes: 4 additions & 4 deletions src/scope_analyzer.py
Expand Up @@ -15,14 +15,14 @@ def get_region_scope(self, view, region, block):
self.view = view

if block == 'meta.function':
region_scope = self.get_token_via_scope(region, "meta.function entity.name.function")
if view.match_selector(region.a, "variable.other.member"):
region_scope = self.get_token_via_scope(region, "meta.class entity.name.class")
else:
region_scope = self.get_token_via_scope(region, "meta.function entity.name.function")

if block == 'meta.class':
region_scope = self.get_token_via_scope(region, "meta.class entity.name.class")

# scope = self.view.scope_name(region_scope.a)
# region_scope_name = self.view.substr(self.view.word(region_scope))
# print(region_scope, "\"%s\"" % region_scope_name, scope)
return region_scope

def get_token_via_scope(self, region, scope):
Expand Down
12 changes: 10 additions & 2 deletions src/state.py
@@ -1,13 +1,21 @@
import sublime

# global vars
settings = {}
syntax_scopes = {}
syntax = None
highlight_enabled = False
highlight_regions = {}
current_selection = None
highlight_tags = {}
selection_lock = False

styles = {
'outline': sublime.DRAW_NO_FILL,
'fill': sublime.DRAW_NO_OUTLINE,
'underline': sublime.DRAW_NO_FILL | sublime.DRAW_NO_OUTLINE | sublime.DRAW_SOLID_UNDERLINE
}

state = {
"current_highlight": None
"syntax_scopes": {},
"current_highlight": {}
}

0 comments on commit 4b4606d

Please sign in to comment.