def act(context, input=None, default=None, **syntaxes): ''' Required action method input dictates what fills the placeholder if there is no selection: - word - line default and syntaxes will replace $EDITOR_SELECTION with a URL escaped version of the selected text (or input, if no selected text) ''' text, range = tea.get_single_selection(context) if text is None: range = tea.get_single_range(context) if input == 'word': text, range = tea.get_word(context, range) elif input == 'line': text, range = tea.get_line(context, range) # If we still don't have text, there's nothing to work with if text is None: return False # URL escape the selected text text = urllib.quote_plus(text) url = tea.select_from_zones(context, range, default, **syntaxes) # Got the URL, let's run the URL # DEPRECATED: please use $EDITOR_SELECTION instead url = url.replace('$SELECTED_TEXT', text) url = url.replace('$EDITOR_SELECTION', text) NSWorkspace.sharedWorkspace().openURL_(NSURL.URLWithString_(url)) # Because this gets passed through to Obj-C, using int prevents beeping return True
def act(context, target=None, source=None, trim=False, discard_indent=False, search_string=None, regex=False): ''' Required action method target dictates what we're looking for: - text - if unspecified, simply selects the source source dictates how to gather the string to search for: - word (word under the caret) - line (line under the caret) - if unspecified, defaults to selection Setting trim=True will cause the source to be trimmed Setting discard_indent=True will cause leading whitespace to be trimmed (unnecessary unless trim=True) search_string will set the string to search for if target is text or zone - $SELECTED_TEXT will be replaced with the source text Setting regex=True will cause search_string to be evaluated as regex ''' range = tea.get_ranges(context)[0] if source == 'word': text, range = tea.get_word(context, range) elif source == 'line': text, range = tea.get_line(context, range) elif range.length > 0: text = tea.get_selection(context, range) # Make sure that we've got some text, even if it's an empty string if text is None: text = '' # Trim the source if trim: if discard_indent: trimmed = tea.trim(context, text, False) else: trimmed = tea.trim(context, text, False, 'end') start = text.find(trimmed) if start != -1: start = range.location + start length = len(trimmed) if source == 'line': # We don't want the linebreak if we're trimming length = length - 1 range = tea.new_range(start, length) text = trimmed if target is not None and text: if search_string is not None: search = search_string.replace('$SELECTED_TEXT', text) else: search = text # Find the start and end points of the substring start = end = None if regex: match = re.search(r'(' + search + r')', context.string()) if match: # Get the start and end points start, end = match.span(1) else: start = context.string().find(search) if start != -1: end = start + len(search) else: start = None # Construct the new target range if start is not None and end is not None: range = tea.new_range(start, end - start) # Set the new range tea.set_selected_range(context, range) return True
def act(controller, bundle, options): ''' Required action method target dictates what we're looking for: - text - if unspecified, simply selects the source source dictates how to gather the string to search for: - word (word under the caret) - line (line under the caret) - if unspecified, defaults to selection Setting trim=True will cause the source to be trimmed Setting discard_indent=True will cause leading whitespace to be trimmed (unnecessary unless trim=True) search_string will set the string to search for if target is text or zone - $SELECTED_TEXT will be replaced with the source text Setting regex=True will cause search_string to be evaluated as regex ''' context = tea.get_context(controller) target = tea.get_option(options, 'target') source = tea.get_option(options, 'source') trim = tea.get_option(options, 'trim', False) discard_indent = tea.get_option(options, 'discard_indent', False) search_string = tea.get_option(options, 'search_string') regex = tea.get_option(options, 'regex', False) range = tea.get_range(context) if source == 'word': text, range = tea.get_word(context, range) elif source == 'line': text, range = tea.get_line(context) elif range.length > 0: text = tea.get_selection(context, range) # Trim the source if trim: if discard_indent: trimmed = tea.trim(context, text, False, preserve_linebreaks=False) else: trimmed = tea.trim(context, text, False, 'end', preserve_linebreaks=False) start = text.find(trimmed) if start != -1: start = range.location + start length = len(trimmed) if source == 'line' and trimmed[-1:] in ['\r\n', '\r', '\n']: # We don't want the linebreak if we're trimming length = length - 1 range = tea.new_range(start, length) text = trimmed if target is not None and text: if search_string is not None: search = search_string.replace('$SELECTED_TEXT', text) else: search = text # Find the start and end points of the substring start = end = None if regex: match = re.search(r'(' + search + r')', context.string()) if match: # Get the start and end points start, end = match.span(1) else: start = context.string().find(search) if start != -1: end = start + len(search) else: start = None # Construct the new target range if start is not None and end is not None: range = tea.new_range(start, end - start) # Set the new range tea.set_selected_range(context, range)
def performActionWithContext_error_(self, context): ''' Gathers the necessary info, populates the environment, and runs the script ''' def execute(file, input): '''Utility function for running the script''' script = subprocess.Popen( [file], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) return script.communicate(str(input)) if self.script is None: tea.log('No script found') return False # Environment variables that won't change with repetition os.putenv('E_SUGARPATH', self.bundle_path) filepath = context.documentContext().fileURL() if filepath is not None: os.putenv('E_FILENAME', filepath.path().lastPathComponent()) if filepath.isFileURL(): os.putenv( 'E_DIRECTORY', filepath.path().stringByDeletingLastPathComponent() ) os.putenv('E_FILEPATH', filepath.path()) root = tea.get_root_zone(context) if root is False: root = '' os.putenv('E_ROOT_ZONE', root) # Set up the preferences prefs = tea.get_prefs(context) os.putenv('E_SOFT_TABS', str(prefs.insertsSpacesForTab())) os.putenv('E_TAB_SIZE', str(prefs.numberOfSpacesForTab())) os.putenv('E_LINE_ENDING', prefs.lineEndingString()) os.putenv('E_XHTML', tea.get_tag_closestring(context)) # Set up the user-defined shell variables defaults = NSUserDefaults.standardUserDefaults() for item in defaults.arrayForKey_('TEAShellVariables'): if 'variable' in item and item['variable'] != '': os.putenv(item['variable'], item['value']) # Initialize our common variables recipe = tea.new_recipe() ranges = tea.get_ranges(context) # Check the user script folder for overrides file = os.path.join(os.path.expanduser( '~/Library/Application Support/Espresso/TEA/Scripts/' ), self.script) if not os.path.exists(file): file = os.path.join(self.bundle_path, 'TEA', self.script) if not os.path.exists(file): # File doesn't exist in the bundle, either, so something is screwy return tea.say( context, 'Error: could not find script', 'TEA could not find the script associated with this action. '\ 'Please contact the Sugar developer, or make sure it is '\ 'installed here:\n\n'\ '~/Library/Application Support/Espresso/TEA/Scripts' ) # There's always at least one range; this thus supports multiple # discontinuous selections for range in ranges: # These environment variables may change with repetition, so reset os.putenv('E_SELECTED_TEXT', str(context.string().substringWithRange_(range)) ) word, wordrange = tea.get_word(context, range) os.putenv('E_CURRENT_WORD', str(word)) os.putenv('E_CURRENT_LINE', str(context.string().substringWithRange_( context.lineStorage().lineRangeForRange_(range) )) ) os.putenv( 'E_LINENUMBER', str(context.lineStorage().lineNumberForIndex_(range.location)) ) os.putenv('E_LINEINDEX', str( range.location - \ context.lineStorage().lineStartIndexForIndex_lineNumber_( range.location, None ) )) active = tea.get_active_zone(context, range) if active is False: active = '' os.putenv('E_ACTIVE_ZONE', str(active)) # Setup STDIN and track the source source = 'input' if self.input == 'selection': input = tea.get_selection(context, range) if input == '': if self.alt == 'document': input = context.string() elif self.alt == 'line': input, range = tea.get_line(context, range) # For this usage, we don't want to pass the final linebreak input = input[:-1] range = tea.new_range(range.location, range.length-1) elif self.alt == 'word': input, range = tea.get_word(context, range) elif self.alt == 'character': input, range = tea.get_character(context, range) source = 'alt' elif self.input == 'document': input = context.string() else: input = '' # Run the script try: output, error = execute(file, input) except: # Most likely cause of failure is lack of executable status try: os.chmod(file, 0755) output, error = execute(file, input) except: # Failed to execute completely, so exit with error return tea.say( context, 'Error: cannot execute script', 'Error: could not execute the script. Please contact '\ 'the Sugar author.' ) # Log errors if error: tea.log(str(error)) # Process the output output = output.decode('utf-8') if self.output == 'document' or \ (source == 'alt' and self.alt == 'document'): docrange = tea.new_range(0, context.string().length()) recipe.addReplacementString_forRange_(output, docrange) break elif self.output == 'text': recipe.addReplacementString_forRange_(output, range) elif self.output == 'snippet': recipe.addDeletedRange_(range) break # If no output, we don't need to go any further if self.output is None: return True # Made it here, so apply the recipe and return if self.undo is not None: recipe.setUndoActionName_(self.undo) recipe.prepare() if recipe.numberOfChanges() > 0: response = context.applyTextRecipe_(recipe) else: response = True if self.output == 'snippet': response = tea.insert_snippet(context, output) return response