712 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			712 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import sublime
 | |
| import sublime_plugin
 | |
| 
 | |
| import re
 | |
| import imp
 | |
| import json
 | |
| import sys
 | |
| import os.path
 | |
| import traceback
 | |
| 
 | |
| BASE_PATH = os.path.abspath(os.path.dirname(__file__))
 | |
| PACKAGES_PATH = sublime.packages_path() or os.path.dirname(BASE_PATH)
 | |
| # EMMET_GRAMMAR = os.path.join(BASE_PATH, 'Emmet.tmLanguage')
 | |
| EMMET_GRAMMAR = 'Packages/%s/Emmet.tmLanguage' % os.path.basename(BASE_PATH)
 | |
| sys.path += [BASE_PATH] + [os.path.join(BASE_PATH, f) for f in ['emmet_completions', 'emmet']]
 | |
| 
 | |
| 
 | |
| # Make sure all dependencies are reloaded on upgrade
 | |
| if 'emmet.reloader' in sys.modules:
 | |
| 	imp.reload(sys.modules['emmet.reloader'])
 | |
| import emmet.reloader
 | |
| 
 | |
| # import completions as cmpl
 | |
| import emmet.pyv8loader as pyv8loader
 | |
| import emmet_completions as cmpl
 | |
| from emmet_completions.meta import HTML_ELEMENTS_ATTRIBUTES, HTML_ATTRIBUTES_VALUES
 | |
| from emmet.context import Context
 | |
| from emmet.context import js_file_reader as _js_file_reader
 | |
| from emmet.pyv8loader import LoaderDelegate
 | |
| 
 | |
| __version__      = '1.1'
 | |
| __core_version__ = '1.0'
 | |
| __authors__      = ['"Sergey Chikuyonok" <serge.che@gmail.com>'
 | |
| 					'"Nicholas Dudfield" <ndudfield@gmail.com>']
 | |
| 
 | |
| is_python3 = sys.version_info[0] > 2
 | |
| 
 | |
| # JS context
 | |
| ctx = None
 | |
| # Emmet Settings
 | |
| settings = None
 | |
| 
 | |
| # Default ST settings
 | |
| user_settings = None
 | |
| 
 | |
| def is_st3():
 | |
| 	return sublime.version()[0] == '3'
 | |
| 
 | |
| def js_file_reader(file_path, use_unicode=True):
 | |
| 	if hasattr(sublime, 'load_resource'):
 | |
| 		rel_path = file_path
 | |
| 		for prefix in [sublime.packages_path(), sublime.installed_packages_path()]:
 | |
| 			if rel_path.startswith(prefix):
 | |
| 				rel_path = os.path.join('Packages', rel_path[len(prefix) + 1:])
 | |
| 				break
 | |
| 
 | |
| 		rel_path = rel_path.replace('.sublime-package', '')
 | |
| 		# for Windows we have to replace slashes
 | |
| 		rel_path = rel_path.replace('\\', '/')
 | |
| 		return sublime.load_resource(rel_path)
 | |
| 
 | |
| 	return _js_file_reader(file_path, use_unicode)
 | |
| 
 | |
| def init():
 | |
| 	"Init Emmet plugin"
 | |
| 	# load settings
 | |
| 	globals()['user_settings'] = sublime.load_settings('Preferences.sublime-settings')
 | |
| 	globals()['settings'] = sublime.load_settings('Emmet.sublime-settings')
 | |
| 	settings.add_on_change('extensions_path', update_settings)
 | |
| 
 | |
| 	# setup environment for PyV8 loading
 | |
| 	pyv8_paths = [
 | |
| 		os.path.join(PACKAGES_PATH, 'PyV8'),
 | |
| 		os.path.join(PACKAGES_PATH, 'PyV8', pyv8loader.get_arch()),
 | |
| 		os.path.join(PACKAGES_PATH, 'PyV8', 'pyv8-%s' % pyv8loader.get_arch())
 | |
| 	]
 | |
| 
 | |
| 	sys.path += pyv8_paths
 | |
| 
 | |
| 	# unpack recently loaded binary, is exists
 | |
| 	for p in pyv8_paths:
 | |
| 		pyv8loader.unpack_pyv8(p)
 | |
| 	
 | |
| 	# provide some contributions to JS
 | |
| 	contrib = {
 | |
| 		'sublime': sublime, 
 | |
| 		'sublimeReplaceSubstring': replace_substring,
 | |
| 		'sublimeGetOption': settings.get
 | |
| 	}
 | |
| 
 | |
| 	# create JS environment
 | |
| 	delegate = SublimeLoaderDelegate()
 | |
| 	globals()['ctx'] = Context(
 | |
| 		files=['../editor.js'], 
 | |
| 		ext_path=settings.get('extensions_path', None), 
 | |
| 		contrib=contrib, 
 | |
| 		logger=delegate.log,
 | |
| 		reader=js_file_reader
 | |
| 	)
 | |
| 
 | |
| 	update_settings()
 | |
| 
 | |
| 	pyv8loader.load(pyv8_paths[1], delegate) 
 | |
| 
 | |
| 	if settings.get('remove_html_completions', False):
 | |
| 		sublime.set_timeout(cmpl.remove_html_completions, 2000)
 | |
| 
 | |
| class SublimeLoaderDelegate(LoaderDelegate):
 | |
| 	def __init__(self, settings=None):
 | |
| 
 | |
| 		if settings is None:
 | |
| 			settings = {}
 | |
| 			for k in ['http_proxy', 'https_proxy', 'timeout']:
 | |
| 				if user_settings.has(k):
 | |
| 					settings[k] = user_settings.get(k, None)
 | |
| 
 | |
| 		LoaderDelegate.__init__(self, settings)
 | |
| 		self.state = None
 | |
| 		self.message = 'Loading PyV8 binary, please wait'
 | |
| 		self.i = 0
 | |
| 		self.addend = 1
 | |
| 		self.size = 8
 | |
| 
 | |
| 	def on_start(self, *args, **kwargs):
 | |
| 		self.state = 'loading'
 | |
| 
 | |
| 	def on_progress(self, *args, **kwargs):
 | |
| 		if kwargs['progress'].is_background:
 | |
| 			return
 | |
| 
 | |
| 		before = self.i % self.size
 | |
| 		after = (self.size - 1) - before
 | |
| 		msg = '%s [%s=%s]' % (self.message, ' ' * before, ' ' * after)
 | |
| 		if not after:
 | |
| 			self.addend = -1
 | |
| 		if not before:
 | |
| 			self.addend = 1
 | |
| 		self.i += self.addend
 | |
| 
 | |
| 		sublime.set_timeout(lambda: sublime.status_message(msg), 0)
 | |
| 
 | |
| 	def on_complete(self, *args, **kwargs):
 | |
| 		self.state = 'complete'
 | |
| 
 | |
| 		if kwargs['progress'].is_background:
 | |
| 			return
 | |
| 
 | |
| 		sublime.set_timeout(lambda: sublime.status_message('PyV8 binary successfully loaded'), 0)
 | |
| 
 | |
| 	def on_error(self, exit_code=-1, thread=None):
 | |
| 		self.state = 'error'
 | |
| 		sublime.set_timeout(lambda: show_pyv8_error(exit_code), 0)
 | |
| 
 | |
| 	def setting(self, name, default=None):
 | |
| 		"Returns specified setting name"
 | |
| 		return self.settings.get(name, default)
 | |
| 
 | |
| 	def log(self, message):
 | |
| 		print('Emmet: %s' % message)
 | |
| 
 | |
| def show_pyv8_error(exit_code):
 | |
| 	if 'PyV8' not in sys.modules:
 | |
| 		sublime.error_message('Error while loading PyV8 binary: exit code %s \nTry to manually install PyV8 from\nhttps://github.com/emmetio/pyv8-binaries' % exit_code)
 | |
| 
 | |
| def active_view():
 | |
| 	return sublime.active_window().active_view()
 | |
| 
 | |
| def check_context(verbose=False):
 | |
| 	"Checks if JS context is completely available"
 | |
| 	if not ctx.js():
 | |
| 		if verbose:
 | |
| 			sublime.message_dialog('Please wait a bit while PyV8 binary is being downloaded')
 | |
| 		return False
 | |
| 
 | |
| 	return True
 | |
| 
 | |
| 
 | |
| def replace_substring(start, end, value, no_indent=False):
 | |
| 	view = active_view()
 | |
| 
 | |
| 	view.sel().clear()
 | |
| 	view.sel().add(sublime.Region(start, end or start)) 
 | |
| 
 | |
| 	if not is_python3:
 | |
| 		value = value.decode('utf-8')
 | |
| 
 | |
| 	# XXX a bit naive indentation control. It handles most common
 | |
| 	# `no_indent` usages like replacing CSS rule content, but may not
 | |
| 	# produce expected result in all possible situations
 | |
| 
 | |
| 	if no_indent:
 | |
| 		line = view.substr(view.line(view.sel()[0]))
 | |
| 		value = unindent_text(value, get_line_padding(line))
 | |
| 
 | |
| 	view.run_command('insert_snippet', {'contents': value})
 | |
| 
 | |
| def unindent_text(text, pad):
 | |
| 	"""
 | |
| 	Removes padding at the beginning of each text's line
 | |
| 	@type text: str
 | |
| 	@type pad: str
 | |
| 	"""
 | |
| 	lines = text.splitlines()
 | |
| 	
 | |
| 	for i,line in enumerate(lines):
 | |
| 		if line.startswith(pad):
 | |
| 			lines[i] = line[len(pad):]
 | |
| 	
 | |
| 	return '\n'.join(lines)
 | |
| 
 | |
| def get_line_padding(line):
 | |
| 	"""
 | |
| 	Returns padding of current editor's line
 | |
| 	@return str
 | |
| 	"""
 | |
| 	m = re.match(r'^(\s+)', line)
 | |
| 	return m and m.group(0) or ''
 | |
| 
 | |
| def update_settings():
 | |
| 	ctx.set_ext_path(settings.get('extensions_path', None))
 | |
| 
 | |
| 	keys = ['snippets', 'preferences', 'syntaxProfiles', 'profiles']
 | |
| 	payload = {}
 | |
| 	for k in keys:
 | |
| 		data = settings.get(k, None)
 | |
| 		if data:
 | |
| 			payload[k] = data
 | |
| 
 | |
| 	ctx.reset()
 | |
| 	ctx.load_user_data(json.dumps(payload))
 | |
| 	ctx.js()
 | |
| 
 | |
| def get_scope(view, pt=-1):
 | |
| 	if pt == -1:
 | |
| 		# use current caret position
 | |
| 		pt = view.sel()[0].begin()
 | |
| 
 | |
| 	if hasattr(view, 'scope_name'):
 | |
| 		return view.scope_name(pt)
 | |
| 
 | |
| 	return view.syntax_name(pt)
 | |
| 
 | |
| def should_perform_action(name, view=None):
 | |
| 	if not view:
 | |
| 		view = active_view()
 | |
| 
 | |
| 	# fallback to old check
 | |
| 	if not view.settings().get('enable_emmet_keymap', True):
 | |
| 		return False
 | |
| 
 | |
| 	disabled_actions = settings.get('disabled_keymap_actions', '')
 | |
| 
 | |
| 	if not disabled_actions: # no disabled actions
 | |
| 		return True
 | |
| 
 | |
| 	if disabled_actions == 'all': # disable all actions
 | |
| 		return False
 | |
| 
 | |
| 	return name not in re.split(r'\s*,\s*', disabled_actions.strip())
 | |
| 
 | |
| def should_handle_tab_key(syntax=None):
 | |
| 	view = active_view()
 | |
| 	scopes = settings.get('disabled_single_snippet_for_scopes', None)
 | |
| 	cur_scope = get_scope(view)
 | |
| 
 | |
| 	if sublime.score_selector(cur_scope, 'source.css'):
 | |
| 		return True
 | |
| 
 | |
| 	if not scopes or not sublime.score_selector(cur_scope, scopes):
 | |
| 		return True
 | |
| 
 | |
| 	abbr = ctx.js().locals.pyExtractAbbreviation()
 | |
| 
 | |
| 	disabled_snippets = settings.get('disabled_single_snippets', '').split()
 | |
| 	if disabled_snippets and abbr in disabled_snippets:
 | |
| 		return False
 | |
| 
 | |
| 	if not re.match(r'^[\w\:%]+$', abbr):
 | |
| 		# it's a complex expression
 | |
| 		return True
 | |
| 
 | |
| 	if re.match(r'^(lorem|lipsum)([a-z]{2})?\d*$', abbr):
 | |
| 		# hardcoded Lorem Ipsum generator
 | |
| 		return True
 | |
| 
 | |
| 	# detect inline CSS
 | |
| 	if syntax is None:
 | |
| 		syntax = ctx.js().locals.pyGetSyntax();
 | |
| 
 | |
| 	if syntax == 'css':
 | |
| 		return True
 | |
| 
 | |
| 	known_tags = settings.get('known_html_tags', '').split()
 | |
| 	if abbr in known_tags or ctx.js().locals.pyHasSnippet(abbr):
 | |
| 		return True
 | |
| 
 | |
| 	return False
 | |
| 
 | |
| def log(message):
 | |
| 	if settings.get('debug', False):
 | |
| 		print('Emmet: %s' % message)
 | |
| 
 | |
| class RunEmmetAction(sublime_plugin.TextCommand):
 | |
| 	def run(self, edit, action=None, **kw):
 | |
| 		run_action(lambda i, sel: ctx.js().locals.pyRunAction(action))
 | |
| 		# ctx.js().locals.pyRunAction(action)
 | |
| 
 | |
| class ActionContextHandler(sublime_plugin.EventListener):
 | |
| 	def on_query_context(self, view, key, op, operand, match_all):
 | |
| 		if not key.startswith('emmet_action_enabled.'):
 | |
| 			return None
 | |
| 
 | |
| 		prefix, name = key.split('.')
 | |
| 		return should_perform_action(name, view)
 | |
| 
 | |
| def get_edit(view, edit_token=None):
 | |
| 	edit = None
 | |
| 	try:
 | |
| 		edit = view.begin_edit()
 | |
| 	except:
 | |
| 		pass
 | |
| 
 | |
| 	if not edit and edit_token:
 | |
| 		try:
 | |
| 			edit = view.begin_edit(edit_token, 'Emmet')
 | |
| 		except Exception as e:
 | |
| 			pass
 | |
| 
 | |
| 	return edit
 | |
| 
 | |
| def run_action(action, view=None):
 | |
| 	if not check_context(True):
 | |
| 		return
 | |
| 
 | |
| 	"Runs Emmet action in multiselection mode"
 | |
| 	if not view:
 | |
| 		view = active_view()
 | |
| 
 | |
| 	region_key = '__emmet__'
 | |
| 	sels = list(view.sel())
 | |
| 	r = ctx.js().locals.pyRunAction
 | |
| 	result = False
 | |
| 
 | |
| 	# edit = get_edit(view, edit_token)
 | |
| 	max_sel_ix = len(sels) - 1
 | |
| 
 | |
| 	try:
 | |
| 		for i, sel in enumerate(reversed(sels)):
 | |
| 			view.sel().clear()
 | |
| 			view.sel().add(sel)
 | |
| 			# run action
 | |
| 			# result = r(name) or result
 | |
| 			result = action(max_sel_ix - i, sel) or result
 | |
| 
 | |
| 			# remember resulting selections
 | |
| 			view.add_regions(region_key,
 | |
| 					(view.get_regions(region_key) + list(view.sel())) , '')
 | |
| 	except Exception as e:
 | |
| 		view.erase_regions(region_key)
 | |
| 		print(traceback.format_exc())
 | |
| 		return
 | |
| 	
 | |
| 
 | |
| 	# output all saved regions as selection
 | |
| 	view.sel().clear()
 | |
| 	for sel in view.get_regions(region_key):
 | |
| 		view.sel().add(sel)
 | |
| 
 | |
| 	view.erase_regions(region_key)
 | |
| 
 | |
| 	# if edit:
 | |
| 		# view.end_edit(edit)
 | |
| 	return result
 | |
| 
 | |
| class TabAndCompletionsHandler():
 | |
| 	def correct_syntax(self, view, syntax='html'):
 | |
| 		return syntax == 'html' and view.match_selector( view.sel()[0].b, cmpl.EMMET_SCOPE )
 | |
| 
 | |
| 	def completion_handler(self, view):
 | |
| 		"Returns completions handler fo current caret position"
 | |
| 		black_list = settings.get('completions_blacklist', [])
 | |
| 
 | |
| 		# A mapping of scopes, sub scopes and handlers, first matching of which
 | |
| 		# is used.
 | |
| 		COMPLETIONS = (
 | |
| 			(cmpl.HTML_INSIDE_TAG, self.html_elements_attributes),
 | |
| 			(cmpl.HTML_INSIDE_TAG_ATTRIBUTE, self.html_attributes_values)
 | |
| 		)
 | |
| 
 | |
| 		pos = view.sel()[0].b
 | |
| 
 | |
| 		# Try to find some more specific contextual abbreviation
 | |
| 		for sub_selector, handler in COMPLETIONS:
 | |
| 			h_name = handler.__name__
 | |
| 			if not black_list or h_name in black_list: continue
 | |
| 			if (view.match_selector(pos,  sub_selector) or
 | |
| 				 view.match_selector(pos - 1,  sub_selector)):
 | |
| 				return handler
 | |
| 
 | |
| 		return None
 | |
| 
 | |
| 	def html_elements_attributes(self, view, prefix, pos):
 | |
| 		tag         = cmpl.find_tag_name(view, pos)
 | |
| 		values      = HTML_ELEMENTS_ATTRIBUTES.get(tag, [])
 | |
| 		return [(v,   '%s\t@%s' % (v,v), '%s="$1"' % v) for v in values]
 | |
| 
 | |
| 	def html_attributes_values(self, view, prefix, pos):
 | |
| 		attr        = cmpl.find_attribute_name(view, pos)
 | |
| 		values      = HTML_ATTRIBUTES_VALUES.get(attr, [])
 | |
| 		return [(v, '%s\t@=%s' % (v,v), v) for v in values]
 | |
| 
 | |
| 	def expand_by_tab(self, view):
 | |
| 		if not check_context():
 | |
| 			return False;
 | |
| 			
 | |
| 		syntax = ctx.js().locals.pyGetSyntax();
 | |
| 		if not should_handle_tab_key(syntax):
 | |
| 			return False
 | |
| 
 | |
| 		# we need to filter out attribute completions if 
 | |
| 		# 'disable_completions' option is not active
 | |
| 		if (not settings.get('disable_completions', False) and 
 | |
| 			self.correct_syntax(view, syntax) and 
 | |
| 			self.completion_handler(view)):
 | |
| 				return None
 | |
| 
 | |
| 		caret_pos = view.sel()[0].begin()
 | |
| 		cur_scope = get_scope(view)
 | |
| 
 | |
| 		# let's see if Tab key expander should be disabled for current scope
 | |
| 		banned_scopes = settings.get('disable_tab_abbreviations_for_scopes', '')
 | |
| 		if banned_scopes and view.score_selector(caret_pos, banned_scopes):
 | |
| 			return None
 | |
| 
 | |
| 		# Sometimes ST2 matcher may incorrectly filter scope context,
 | |
| 		# check it against special regexp
 | |
| 		banned_regexp = settings.get('disable_tab_abbreviations_for_regexp', None)
 | |
| 		if banned_regexp and re.search(banned_regexp, cur_scope):
 | |
| 			return None
 | |
| 		
 | |
| 		return run_action(lambda i, sel: ctx.js().locals.pyRunAction('expand_abbreviation'))
 | |
| 		
 | |
| 		# view.run_command('run_emmet_action',
 | |
| 		# 						{'action':'expand_abbreviation'})
 | |
| 
 | |
| class ExpandAbbreviationByTab(sublime_plugin.TextCommand):
 | |
| 	def run(self, edit, **kw):
 | |
| 		if settings.get('use_old_tab_handler', False):
 | |
| 			return
 | |
| 			
 | |
| 		view = active_view()
 | |
| 		h = TabAndCompletionsHandler()
 | |
| 		if not h.expand_by_tab(view):
 | |
| 			# try to mimic default Tab behaviour of Sublime Text
 | |
| 			view.run_command('insert_best_completion', {
 | |
| 				'default': '\t',
 | |
| 				'exact': user_settings.get('tab_completion', True)
 | |
| 			})
 | |
| 
 | |
| 
 | |
| class TabExpandHandler(sublime_plugin.EventListener):
 | |
| 	def on_query_context(self, view, key, op, operand, match_all):
 | |
| 		if key != 'is_abbreviation':
 | |
| 			return None
 | |
| 
 | |
| 		if settings.get('use_old_tab_handler', False):
 | |
| 			h = TabAndCompletionsHandler()
 | |
| 			return h.expand_by_tab(view)
 | |
| 
 | |
| 		return check_context()
 | |
| 
 | |
| 	def on_query_completions(self, view, prefix, locations):
 | |
| 		h = TabAndCompletionsHandler()
 | |
| 		if view.match_selector(locations[0], settings.get('css_completions_scope', '')) and check_context():
 | |
| 			l = []
 | |
| 			if settings.get('show_css_completions', False):
 | |
| 				completions = ctx.js().locals.pyGetCSSCompletions()
 | |
| 				if completions:
 | |
| 					for p in completions:
 | |
| 						l.append(('%s\t%s' % (p['k'], p['label']), p['v']))
 | |
| 
 | |
| 			if not l:
 | |
| 				return []
 | |
| 
 | |
| 			return (l, sublime.INHIBIT_WORD_COMPLETIONS | sublime.INHIBIT_EXPLICIT_COMPLETIONS)
 | |
| 
 | |
| 		if not h.correct_syntax(view) or settings.get('disable_completions', False):
 | |
| 			return []
 | |
| 
 | |
| 		handler = h.completion_handler(view)
 | |
| 		if handler:
 | |
| 			pos = view.sel()[0].b
 | |
| 			completions = handler(view, prefix, pos)
 | |
| 			return completions
 | |
| 
 | |
| 		return []
 | |
| 		
 | |
| 
 | |
| class CommandsAsYouTypeBase(sublime_plugin.TextCommand):
 | |
| 	input_message         = "Enter Input"
 | |
| 	default_input         = ""
 | |
| 	process_panel_input   = lambda s, i: i.title()
 | |
| 
 | |
| 	# Note that this must be of form `Packages/$Package/Emmet.tmLanguage` on ST3
 | |
| 	# NOT an absolute path!
 | |
| 	panel_grammar         = EMMET_GRAMMAR
 | |
| 
 | |
| 	def is_enabled(self):
 | |
| 		return True
 | |
| 
 | |
| 	def run_command(self, edit, view, processed_input):
 | |
| 		if '\n' in processed_input:
 | |
| 			for sel in view.sel():
 | |
| 				trailing = sublime.Region(sel.end(), view.line(sel).end())
 | |
| 				if view.substr(trailing).isspace():
 | |
| 					view.erase(edit, trailing)
 | |
| 
 | |
| 		if not is_python3:
 | |
| 			processed_input = processed_input.decode('utf-8')
 | |
| 		view.run_command('insert_snippet', { 'contents': processed_input })
 | |
| 
 | |
| 	def on_panel_change(self, abbr):
 | |
| 		if not abbr and self.erase:
 | |
| 			self.undo()
 | |
| 			self.erase = False
 | |
| 			return
 | |
| 
 | |
| 		def inner_insert():
 | |
| 			self.view.run_command(self.name(), dict(panel_input=abbr))
 | |
| 			# self.view.run_command('hide_auto_complete')
 | |
| 
 | |
| 		self.undo()
 | |
| 		sublime.set_timeout(inner_insert, 0)
 | |
| 
 | |
| 	def undo(self):
 | |
| 		if self.erase:
 | |
| 			sublime.set_timeout(lambda: self.view.run_command('undo'), 0)
 | |
| 
 | |
| 	def remember_sels(self, view):
 | |
| 		self._sels = list(view.sel())
 | |
| 		self._sel_items = []
 | |
| 
 | |
| 		for sel in self._sels:
 | |
| 			# selection should be unindented in order to get desired result
 | |
| 			line = view.substr(view.line(sel))
 | |
| 			s = view.substr(sel)
 | |
| 			self._sel_items.append(unindent_text(s, get_line_padding(line)))
 | |
| 
 | |
| 	def on_panel_done(self, abbr):
 | |
| 		pass
 | |
| 
 | |
| 	def run(self, edit, panel_input=None, **kwargs):
 | |
| 
 | |
| 		if panel_input is None:
 | |
| 			self.setup(edit, self.view, **kwargs)
 | |
| 			self.erase = False
 | |
| 
 | |
| 			panel = self.view.window().show_input_panel (
 | |
| 				self.input_message,
 | |
| 				self.default_input,
 | |
| 				self.on_panel_done,              # on_done
 | |
| 				self.on_panel_change,           # on_change
 | |
| 				self.undo)                       # on_cancel
 | |
| 
 | |
| 			panel.sel().clear()
 | |
| 			panel.sel().add(sublime.Region(0, panel.size()))
 | |
| 
 | |
| 			if self.panel_grammar:
 | |
| 				panel.set_syntax_file(self.panel_grammar)
 | |
| 				panel_setting = panel.settings().set
 | |
| 
 | |
| 				panel_setting('line_numbers',   False)
 | |
| 				panel_setting('gutter',         False)
 | |
| 				panel_setting('auto_complete',  False)
 | |
| 				panel_setting('tab_completion', False)
 | |
| 		else:
 | |
| 			self.run_on_input(edit, self.view, panel_input)
 | |
| 
 | |
| 	def setup(self, edit, view, **kwargs):
 | |
| 		pass
 | |
| 
 | |
| 	def run_on_input(self, edit, view, panel_input):
 | |
| 		view = self.view
 | |
| 		cmd_input = self.process_panel_input(panel_input) or ''
 | |
| 		try:
 | |
| 			self.erase = self.run_command(edit, view, cmd_input) is not False
 | |
| 		except:
 | |
| 			pass
 | |
| 
 | |
| class WrapAsYouType(CommandsAsYouTypeBase):
 | |
| 	default_input = 'div'
 | |
| 	_prev_output = ''
 | |
| 	input_message = "Enter Wrap Abbreviation: "
 | |
| 
 | |
| 	def setup(self, edit, view, **kwargs):
 | |
| 		self._prev_output = ''
 | |
| 		
 | |
| 		if len(view.sel()) == 1:
 | |
| 			# capture wrapping context (parent HTML element) 
 | |
| 			# if there is only one selection
 | |
| 			r = ctx.js().locals.pyCaptureWrappingRange()
 | |
| 			if r:
 | |
| 				view.sel().clear()
 | |
| 				view.sel().add(sublime.Region(r[0], r[1]))
 | |
| 				view.show(view.sel())
 | |
| 
 | |
| 		self.remember_sels(view)
 | |
| 
 | |
| 	# override method to correctly wrap abbreviations
 | |
| 	def run_on_input(self, edit, view, abbr):
 | |
| 	# def _real_insert(self, abbr):
 | |
| 		# view = self.view
 | |
| 		# self.edit = get_edit(view, self.edit_token)
 | |
| 
 | |
| 		self.erase = True
 | |
| 
 | |
| 		# restore selections
 | |
| 		view.sel().clear()
 | |
| 		for sel in self._sels:
 | |
| 			view.sel().add(sel)
 | |
| 
 | |
| 		def ins(i, sel):
 | |
| 			try:
 | |
| 				self._prev_output = ctx.js().locals.pyWrapAsYouType(abbr, self._sel_items[i])
 | |
| 				# self.run_command(view, output)
 | |
| 			except Exception:
 | |
| 				"dont litter the console"
 | |
| 
 | |
| 			self.run_command(edit, view, self._prev_output)
 | |
| 
 | |
| 		run_action(ins, view)
 | |
| 		# if self.edit:
 | |
| 		# 	view.end_edit(self.edit)
 | |
| 
 | |
| class ExpandAsYouType(WrapAsYouType):
 | |
| 	default_input = 'div'
 | |
| 	input_message = "Enter Abbreviation: "
 | |
| 
 | |
| 	def setup(self, edit, view, **kwargs):
 | |
| 		# adjust selection to non-space bounds
 | |
| 		sels = []
 | |
| 		for s in view.sel():
 | |
| 			text = view.substr(s)
 | |
| 			a = s.a + len(text) - len(text.lstrip())
 | |
| 			b = s.b - len(text) + len(text.rstrip())
 | |
| 
 | |
| 			sels.append(sublime.Region(a, b))
 | |
| 
 | |
| 		view.sel().clear()
 | |
| 		for s in sels:
 | |
| 			view.sel().add(s)
 | |
| 			
 | |
| 		self.remember_sels(active_view())
 | |
| 
 | |
| 
 | |
| class EnterKeyHandler(sublime_plugin.EventListener):
 | |
| 	def on_query_context(self, view, key, op, operand, match_all):
 | |
| 		if key != 'clear_fields_on_enter_key':
 | |
| 			return None
 | |
| 
 | |
| 		if settings.get('clear_fields_on_enter_key', False):
 | |
| 			view.run_command('clear_fields')
 | |
| 
 | |
| 		return True
 | |
| 
 | |
| 
 | |
| class RenameTag(sublime_plugin.TextCommand):
 | |
| 	def run(self, edit, **kw):
 | |
| 		if not check_context(True):
 | |
| 			return
 | |
| 
 | |
| 		view = active_view()
 | |
| 		sels = list(view.sel())
 | |
| 		sel_cleared = False
 | |
| 		for s in sels:
 | |
| 			ranges = ctx.js().locals.pyGetTagNameRanges(s.begin())
 | |
| 			if ranges:
 | |
| 				if not sel_cleared:
 | |
| 					view.sel().clear()
 | |
| 					sel_cleared = True
 | |
| 					
 | |
| 				for r in ranges:
 | |
| 					view.sel().add(sublime.Region(r[0], r[1]))
 | |
| 				view.show(view.sel())
 | |
| 
 | |
| class EmmetInsertAttribute(sublime_plugin.TextCommand):
 | |
| 	def run(self, edit, attribute=None, **kw):
 | |
| 		if not attribute:
 | |
| 			return
 | |
| 
 | |
| 		view = active_view()
 | |
| 		prefix = ''
 | |
| 		if view.sel():
 | |
| 			sel = view.sel()[0]
 | |
| 			if not view.substr(sublime.Region(sel.begin() - 1, sel.begin())).isspace():
 | |
| 				prefix = ' '
 | |
| 
 | |
| 		view.run_command('insert_snippet', {'contents': '%s%s="$1"' % (prefix, attribute)})
 | |
| 
 | |
| class EmmetResetContext(sublime_plugin.TextCommand):
 | |
| 	def run(self, edit, **kw):
 | |
| 		update_settings()
 | |
| 
 | |
| def plugin_loaded():
 | |
| 	sublime.set_timeout(init, 200)
 | |
| 
 | |
| ##################
 | |
| # Init plugin
 | |
| if not is_python3:
 | |
| 	init()
 | |
| 
 |