def __init__(self, parent, project=None): QPlainTextEdit.__init__(self) EditorGeneric.__init__(self) BaseCentralWidget.__init__(self) self.parent = parent self.completer = Completer(self, project) self.setWordWrapMode(QTextOption.NoWrap) doc = self.document() option = QTextOption() option.setFlags(QTextOption.ShowTabsAndSpaces) doc.setDefaultTextOption(option) self.setDocument(doc) self.set_default_font() #file modification time POSIX self._mtime = None #Flag to dont bug the user when answer 'dont show the modification dialog' self.ask_if_externally_modified = True self.lineNumberArea = self.LineNumberArea(self) self.viewport().installEventFilter(self) self.highlighter = None styles.set_style(self, 'editor') self.connect(self, SIGNAL("cursorPositionChanged()"), self.highlight_current_line) self.connect(self, SIGNAL("modificationChanged(bool)"), self.modif_changed) self.highlight_current_line()
def __init__(self, namespace=None): if namespace is not None: namespace = namespace() InteractiveInterpreter.__init__(self, namespace) self.output_trap = OutputTrap() self.completer = Completer(self.locals) self.input_count = 0 self.interrupted = False
def __init__(self, target, mode): self.version = '0.0.5' self.target = target self.mode = mode self.xtype = 'bufferoverflow' self.offset = 1 self.nops = 0 self.shellcode = '' self.lenght = 0 self.addr1 = None self.addr2 = None self.arch = 'x86' self.port = 0 if self.target: self.p1 = Popen(['gdb', "--silent", "{}".format(self.target)], stdin=PIPE, stdout=PIPE, bufsize=1) gdbout = self.p1.stdout.readline() else: self.p1 = Popen(['gdb', '--silent'], stdin=PIPE, stdout=PIPE, bufsize=1) #gdbout = self.p1.stdout.readline() completer = Completer(".gdb_history", "xploit")
def _coll(content, arg): """ List all plugin collections. """ colls = Completer([])._get_collections() print('\n') for c in colls: print('%s\n %s' % ('-' * 40, c)) print('-' * 40, '\n') return content
def __init__(self, locals = __builtin__.globals()): InteractiveConsole.__init__(self, locals) self.stdout = sys.stdout self.stderr = sys.stderr self.pipe = Pipe() self.completer = Completer(locals)
def main(): print("Running the configurator") # required for travis tests if len(sys.argv) > 2 and sys.argv[-2] == 'scripts/configurator_tests/': sys.argv = [sys.argv[:-2]] args = parsers._config_arg_parser() if args.error: utils.error_level = 1 print("Starting Savu Config tool (please wait for prompt)") _reduce_logging_level() content = Content(level="all" if args.disp_all else 'user') with warnings.catch_warnings(): warnings.simplefilter("ignore") content.failed = utils.populate_plugins(error_mode=args.error, examples=args.examples) comp = Completer(commands=commands, plugin_list=pu.plugins) utils._set_readline(comp.complete) # if file flag is passed then open it here if args.file: commands['open'](content, args.file) print("\n*** Press Enter for a list of available commands. ***\n") utils.load_history_file(utils.histfile) while True: try: in_list = raw_input(">>> ").strip().split(' ', 1) except KeyboardInterrupt: print() continue command, arg = in_list if len(in_list) == 2 else in_list + [''] command = command if command else 'help' if command not in commands: print("I'm sorry, that's not a command I recognise. Press Enter " "for a list of available commands.") else: content = commands[command](content, arg) if content.is_finished(): break print("Thanks for using the application")
def main(): """ Start the Slack Client """ os.system("clear; figlet 'Slack Gitsin' | lolcat") history = FileHistory(os.path.expanduser("~/.slackHistory")) while True: text = prompt("slack> ", history=history, auto_suggest=AutoSuggestFromHistory(), on_abort=AbortAction.RETRY, style=DocumentStyle, completer=Completer(fuzzy_match=False, text_utils=TextUtils()), complete_while_typing=Always(), get_bottom_toolbar_tokens=get_bottom_toolbar_tokens, key_bindings_registry=manager.registry, accept_action=AcceptAction.RETURN_DOCUMENT ) slack = Slack(text) slack.run_command()
def main(): # required for travis tests if len(sys.argv) > 2 and sys.argv[-2] == 'scripts/configurator_tests/': sys.argv = [sys.argv[:-2]] args = parsers._config_arg_parser() if args.error: utils.error_level = 1 print("Starting Savu Config tool (please wait for prompt)") utils.populate_plugins() comp = Completer(commands=commands, plugin_list=pu.plugins) utils._set_readline(comp.complete) content = Content(level="all" if args.disp_all else 'user') # if file flag is passed then open it here if args.file: commands['open'](content, args.file) print("\n*** Press Enter for a list of available commands. ***\n") while True: in_list = raw_input(">>> ").strip().split(' ', 1) command, arg = in_list if len(in_list) is 2 else in_list + [''] command = command if command else 'help' if command not in commands: print("I'm sorry, that's not a command I recognise. Press Enter " "for a list of available commands.") else: content = commands[command](content, arg) if content.is_finished(): break # write the history to the history file utils.readline.write_history_file(utils.histfile) print("Thanks for using the application")
def play_next(): if __last_played: keys = COUBS.keys() i = keys.index(__last_played) if i < len(COUBS) - 1: play(COUBS[keys[i + 1]]['permalink']) else: play(COUBS[keys[0]]['permalink']) elif len(COUBS) > 0: play(COUBS.itervalues().next()['permalink']) else: print 'nothing to play, get some coubs using get command' if __name__ == '__main__': readline.set_completer(Completer(__autocomplete_dict).complete) if sys.platform == 'darwin': readline.parse_and_bind('bind ^I rl_complete') else: readline.parse_and_bind('tab: complete') print """ Howdy! Start with \"get newest\" command and \"play\" some coubs, e.g. \"play 2vf1v\". To quit player screen press \"q\". Btw, autocomplete activated. """ while True: x = raw_input('> ') if x.startswith('get hot'):
class Interpreter(InteractiveInterpreter): def __init__(self, namespace=None): if namespace is not None: namespace = namespace() InteractiveInterpreter.__init__(self, namespace) self.output_trap = OutputTrap() self.completer = Completer(self.locals) self.input_count = 0 self.interrupted = False def evaluate(self, input_string): """give the input_string to the python interpreter in the usernamespace""" self.output_trap.set() command_count = self._runcommands(input_string) stdout, stderr = self.output_trap.get_values() self.output_trap.reset() self.input_count += 1 result = protocol.result_dict(input_string, stdout, in_count=self.input_count, cmd_count=command_count, err=stderr) return result def introspect(self, input_string): """See what information there is about this objects methods and attributes.""" info = introspect(input_string) def complete(self, input_string): """ Complete a name or attribute. """ reName = "([a-zA-Z_][a-zA-Z_0-9]*)$" reAttribute = "([a-zA-Z_][a-zA-Z_0-9]*[.]+[a-zA-Z_.0-9]*)$" nameMatch = re.match(reName, input_string) attMatch = re.match(reAttribute, input_string) if nameMatch: matches = self.completer.global_matches(input_string) return {'out':matches} if attMatch: matches = self.completer.attr_matches(input_string) return {'out':matches} return {'out':[]} def complete_name(self, input_string): """See what possible completions there are for this object (input_string).""" matches = self.completer.global_matches(input_string) # return ' '.join(matches) return matches def complete_attr(self, input_string): matches = self.completer.attr_matches(input_string) return matches # #----------------------------------------------- def _runcommands(self, input_string): """input_string could contain multiple lines, multiple commands, or multiple multiline commands. This method builds a compiled command line by line until a complete command has been compiled. Once it has a complete command, it execs it in the username space and the output is stored in the output trap. There may be more than one command; the number of complete commands is counted (Based off of ipython1.core.shell.InteractiveShell._runlines)""" command_buffer = [] command_count = 0 if self.interrupted: print>>sys.stderr, 'Aborted.' #sys.stderr.write('Aborted') return command_count lines = input_string.split('\n') lines = [l for l in lines if len(l) > 0] more = False for line in lines: line = self._pre_execute_filter(line) command_buffer.append(line) if line or more: torun = '\n'.join(command_buffer) try: more = self.runsource(torun, symbol='exec') except OperationAborted, e: print>>sys.stderr, e.value #sys.stderr.write(e.value) # XXX This could be bad if something other than the # kernelConnection triggers an interrupt #self.interrupted = True return command_count if more: pass else: command_buffer = [] command_count += 1 more = False if more: command_buffer.append('\n') torun = '\n'.join(command_buffer) more = self.runsource(torun) return command_count
class Tab(QWidget): """Tab in the QTableWidget where user executes query and sees the result.""" # ---------------------------------------------------------------------- def __init__(self): """Initialize Tab with layout and behavior.""" super(Tab, self).__init__() # regex pattern for SQL query block comments self.block_comment_re = re.compile( r'(^)?[^\S\n]*/(?:\*(.*?)\*/[^\S\n]*|/[^\n]*)($)?', re.DOTALL | re.MULTILINE) main_layout = QVBoxLayout(self) # define gdb props self.gdb = None self.gdb_items = None self.gdb_columns_names = None self.gdb_schemas = None # connected geodatabase path toolbar self.connected_gdb_path_label = QLabel('') self.connected_gdb_path_label.setTextInteractionFlags( Qt.TextSelectableByMouse) self.connected_gdb_path_label.setToolTip( 'Connected geodatabase that queries will be run against') self.connected_gdb_path_label.setText(not_connected_to_gdb_message) self.browse_to_gdb = QPushButton('Browse') self.browse_to_gdb.setShortcut(QKeySequence('Ctrl+B')) self.browse_to_gdb.clicked.connect( lambda evt, arg=True: self.connect_to_geodatabase( evt, triggered_with_browse=True)) self.gdb_sql_dialect_combobox = QComboBox() for dialect in sql_dialects_names: self.gdb_sql_dialect_combobox.addItem(dialect) self.gdb_browse_toolbar = QToolBar() self.gdb_browse_toolbar.setMaximumHeight(50) self.gdb_browse_toolbar.addWidget(self.browse_to_gdb) self.gdb_browse_toolbar.addWidget(self.connected_gdb_path_label) self.gdb_browse_toolbar.addSeparator() self.gdb_browse_toolbar.addWidget(self.gdb_sql_dialect_combobox) # table with results self.table = ResultTable() # execute SQL query self.execute = QAction('Execute', self) self.execute.setShortcuts( [QKeySequence('F5'), QKeySequence('Ctrl+Return')]) self.execute.triggered.connect(self.run_query) self.addAction(self.execute) # enter a SQL query self.query = TextEditor() self.query.setPlainText('') font = self.query.font() font.setFamily('Consolas') font.setStyleHint(QFont.Monospace) # TODO: add line numbers to the text editor font.setPointSize(14) self.query.setFont(font) self.query.setTabStopWidth(20) self.highlighter = Highlighter(self.query.document()) # TODO select block of text - Ctrl+/ and they become comments self.completer = Completer() self.query.set_completer(self.completer.completer) # errors panel to show if query fails to execute properly self.errors_panel = QPlainTextEdit() font = self.query.font() font.setPointSize(12) self.errors_panel.setStyleSheet('color:red') self.errors_panel.setFont(font) self.errors_panel.hide() # splitter between the toolbar, query window, and the result set table splitter = QSplitter(Qt.Vertical) splitter.addWidget(self.gdb_browse_toolbar) splitter.addWidget(self.query) splitter.addWidget(self.table) splitter.addWidget(self.errors_panel) # add the settings after the widget have been added splitter.setCollapsible(0, True) splitter.setCollapsible(1, False) splitter.setCollapsible(2, False) splitter.setCollapsible(3, False) splitter.setStretchFactor(0, 3) splitter.setStretchFactor(1, 7) splitter.setSizes((100, 200, 300)) self.table.hide() # TOC self.toc = QTreeWidget() self.toc.setHeaderHidden(True) # second splitter between the TOC to the left and the query/table to the # right toc_splitter = QSplitter(Qt.Horizontal) toc_splitter.addWidget(self.toc) toc_splitter.addWidget(splitter) toc_splitter.setCollapsible(0, True) toc_splitter.setSizes((200, 800)) # set the TOC vs data panel main_layout.addWidget(toc_splitter) margins = QMargins() margins.setBottom(10) margins.setLeft(10) margins.setRight(10) margins.setTop(10) main_layout.setContentsMargins(margins) self.setLayout(main_layout) QApplication.setStyle(QStyleFactory.create('Cleanlooks')) self.show() return # ---------------------------------------------------------------------- def connect_to_geodatabase(self, evt, triggered_with_browse=True): """Connect to geodatabase by letting user browse to a gdb folder.""" if triggered_with_browse: gdb_connect_dialog = QFileDialog(self) gdb_connect_dialog.setFileMode(QFileDialog.Directory) gdb_path = gdb_connect_dialog.getExistingDirectory() # TODO: add a filter to show only .gdb folders? # https://stackoverflow.com/questions/4893122/filtering-in-qfiledialog if gdb_path and gdb_path.endswith('.gdb'): self.gdb = Geodatabase(gdb_path) if self.gdb.is_valid(): self.connected_gdb_path_label.setText(self.gdb.path) self._set_gdb_items_highlight() self._set_gdb_items_complete() self._fill_toc() else: msg = QMessageBox() msg.setText('This is not a valid file geodatabase') msg.setWindowTitle('Validation error') msg.setStandardButtons(QMessageBox.Ok) msg.exec_() else: if self.gdb.is_valid(): self._set_gdb_items_highlight() self._set_gdb_items_complete() return # ---------------------------------------------------------------------- def wheelEvent(self, event): # noqa: N802 """Override built-in method to handle mouse wheel scrolling. Necessary to do when the tab is focused. """ modifiers = QApplication.keyboardModifiers() if modifiers == Qt.ControlModifier: if event.angleDelta().y() > 0: # scroll forward self.query.zoomIn(1) else: self.query.zoomOut(1) return # ---------------------------------------------------------------------- def run_query(self): """Run SQL query and draw the record set and call table drawing.""" if not self.gdb: self.print_sql_execute_errors(not_connected_to_gdb_message) return try: if not self.gdb.is_valid(): return # use the text of what user selected, if none -> need to run the # whole query part_sql_query = self.query.textCursor().selection().toPlainText() if part_sql_query: sql_query = part_sql_query else: sql_query = self.query.toPlainText() if sql_query: # removing block comments and single line comments sql_query = self.block_comment_re.sub( self._strip_block_comments, sql_query) sql_query = self._strip_single_comments(sql_query) else: return # TODO: add threading to allow user to cancel a long running query QApplication.setOverrideCursor(Qt.WaitCursor) start_time = time.time() self.gdb.open_connection() res, errors = self.gdb.execute_sql( sql_query, self.gdb_sql_dialect_combobox.currentText()) end_time = time.time() if errors: self.print_sql_execute_errors(errors) if res: self.table.show() self.errors_panel.hide() self.draw_result_table(res) msg = 'Executed in {exec_time:.1f} secs | {rows} rows'.format( exec_time=end_time - start_time, rows=self.table.table_data.number_layer_rows) self.update_app_status_bar(msg) except Exception as err: print(err) finally: QApplication.restoreOverrideCursor() return # ---------------------------------------------------------------------- def result_should_include_geometry(self): """Get the setting defining whether to include the geometry column.""" try: return self.parentWidget().parentWidget().parentWidget( ).do_include_geometry.isChecked() except Exception: return True # ---------------------------------------------------------------------- def update_app_status_bar(self, message): """Update app status bar with the execution result details.""" try: self.parentWidget().parentWidget().parentWidget().statusBar( ).showMessage(message) except Exception: pass return # ---------------------------------------------------------------------- def draw_result_table(self, res): """Draw table with the record set received from the geodatabase.""" geom_col_name = res.GetGeometryColumn( ) # shape col was in the sql query self.geometry_isin_query = bool(geom_col_name) self.table.draw_result(res, show_shapes=bool( self.result_should_include_geometry())) self.table.view.resizeColumnsToContents() return # ---------------------------------------------------------------------- def print_sql_execute_errors(self, err): """Print to a special panel errors that occurred during execution.""" self.table.hide() self.errors_panel.show() self.errors_panel.setPlainText(err) return # ---------------------------------------------------------------------- def _set_gdb_items_highlight(self): """Set completer and highlight properties for geodatabase items.""" self.gdb_items = self.gdb.get_items() self.highlighter.set_highlight_rules_gdb_items(self.gdb_items, 'Table') self.gdb_schemas = self.gdb.get_schemas() self.gdb_columns_names = sorted(list( set( itertools.chain.from_iterable( [i.keys() for i in self.gdb_schemas.values()]))), key=lambda x: x.lower()) # ---------------------------------------------------------------------- def _set_gdb_items_complete(self): """Update completer rules to include geodatabase items.""" self.completer.update_completer_string_list(self.gdb_items + self.gdb_columns_names) self.highlighter.set_highlight_rules_gdb_items(self.gdb_columns_names, 'Column') return # ---------------------------------------------------------------------- def _fill_toc(self): """Fill TOC with geodatabase datasets and columns.""" self.toc.clear() if not self.gdb_items: return for tbl_name in sorted(self.gdb_items, key=lambda i: i.lower()): if tbl_name.islower() or tbl_name.isupper(): item = QTreeWidgetItem([tbl_name.title()]) else: item = QTreeWidgetItem([tbl_name]) font = QFont() font.setBold(True) item.setFont(0, font) for col_name, col_type in sorted( self.gdb_schemas[tbl_name].items()): if col_name.islower() or col_name.isupper(): col_name = col_name.title() item_child = QTreeWidgetItem( ['{0} ({1})'.format(col_name, col_type)]) item.addChild(item_child) self.toc.addTopLevelItem(item) return # ---------------------------------------------------------------------- def _do_toc_hide_show(self): """Hide TOC with tables and columns.""" if self.toc.isVisible(): self.toc.setVisible(False) else: self.toc.setVisible(True) return # ---------------------------------------------------------------------- def _strip_block_comments(self, sql_query): """Strip the block comments in SQL query.""" start, mid, end = sql_query.group(1, 2, 3) if mid is None: # this is a single-line comment return '' elif start is not None or end is not None: # this is a multi-line comment at start/end of a line return '' elif '\n' in mid: # this is a multi-line comment with line break return '\n' else: # this is a multi-line comment without line break return ' ' # ---------------------------------------------------------------------- def _strip_single_comments(self, sql_query): """Strip the single line comments in SQL query.""" clean_query = [] for line in sql_query.rstrip().split('\n'): clean_line = line.split('--')[0] if clean_line: clean_query.append(clean_line) return ' '.join([line for line in clean_query])
def __init__(self): """Initialize Tab with layout and behavior.""" super(Tab, self).__init__() # regex pattern for SQL query block comments self.block_comment_re = re.compile( r'(^)?[^\S\n]*/(?:\*(.*?)\*/[^\S\n]*|/[^\n]*)($)?', re.DOTALL | re.MULTILINE) main_layout = QVBoxLayout(self) # define gdb props self.gdb = None self.gdb_items = None self.gdb_columns_names = None self.gdb_schemas = None # connected geodatabase path toolbar self.connected_gdb_path_label = QLabel('') self.connected_gdb_path_label.setTextInteractionFlags( Qt.TextSelectableByMouse) self.connected_gdb_path_label.setToolTip( 'Connected geodatabase that queries will be run against') self.connected_gdb_path_label.setText(not_connected_to_gdb_message) self.browse_to_gdb = QPushButton('Browse') self.browse_to_gdb.setShortcut(QKeySequence('Ctrl+B')) self.browse_to_gdb.clicked.connect( lambda evt, arg=True: self.connect_to_geodatabase( evt, triggered_with_browse=True)) self.gdb_sql_dialect_combobox = QComboBox() for dialect in sql_dialects_names: self.gdb_sql_dialect_combobox.addItem(dialect) self.gdb_browse_toolbar = QToolBar() self.gdb_browse_toolbar.setMaximumHeight(50) self.gdb_browse_toolbar.addWidget(self.browse_to_gdb) self.gdb_browse_toolbar.addWidget(self.connected_gdb_path_label) self.gdb_browse_toolbar.addSeparator() self.gdb_browse_toolbar.addWidget(self.gdb_sql_dialect_combobox) # table with results self.table = ResultTable() # execute SQL query self.execute = QAction('Execute', self) self.execute.setShortcuts( [QKeySequence('F5'), QKeySequence('Ctrl+Return')]) self.execute.triggered.connect(self.run_query) self.addAction(self.execute) # enter a SQL query self.query = TextEditor() self.query.setPlainText('') font = self.query.font() font.setFamily('Consolas') font.setStyleHint(QFont.Monospace) # TODO: add line numbers to the text editor font.setPointSize(14) self.query.setFont(font) self.query.setTabStopWidth(20) self.highlighter = Highlighter(self.query.document()) # TODO select block of text - Ctrl+/ and they become comments self.completer = Completer() self.query.set_completer(self.completer.completer) # errors panel to show if query fails to execute properly self.errors_panel = QPlainTextEdit() font = self.query.font() font.setPointSize(12) self.errors_panel.setStyleSheet('color:red') self.errors_panel.setFont(font) self.errors_panel.hide() # splitter between the toolbar, query window, and the result set table splitter = QSplitter(Qt.Vertical) splitter.addWidget(self.gdb_browse_toolbar) splitter.addWidget(self.query) splitter.addWidget(self.table) splitter.addWidget(self.errors_panel) # add the settings after the widget have been added splitter.setCollapsible(0, True) splitter.setCollapsible(1, False) splitter.setCollapsible(2, False) splitter.setCollapsible(3, False) splitter.setStretchFactor(0, 3) splitter.setStretchFactor(1, 7) splitter.setSizes((100, 200, 300)) self.table.hide() # TOC self.toc = QTreeWidget() self.toc.setHeaderHidden(True) # second splitter between the TOC to the left and the query/table to the # right toc_splitter = QSplitter(Qt.Horizontal) toc_splitter.addWidget(self.toc) toc_splitter.addWidget(splitter) toc_splitter.setCollapsible(0, True) toc_splitter.setSizes((200, 800)) # set the TOC vs data panel main_layout.addWidget(toc_splitter) margins = QMargins() margins.setBottom(10) margins.setLeft(10) margins.setRight(10) margins.setTop(10) main_layout.setContentsMargins(margins) self.setLayout(main_layout) QApplication.setStyle(QStyleFactory.create('Cleanlooks')) self.show() return
class Editor(QPlainTextEdit, EditorGeneric, BaseCentralWidget): def __init__(self, parent, project=None): QPlainTextEdit.__init__(self) EditorGeneric.__init__(self) BaseCentralWidget.__init__(self) self.parent = parent self.completer = Completer(self, project) self.setWordWrapMode(QTextOption.NoWrap) doc = self.document() option = QTextOption() option.setFlags(QTextOption.ShowTabsAndSpaces) doc.setDefaultTextOption(option) self.setDocument(doc) self.set_default_font() #file modification time POSIX self._mtime = None #Flag to dont bug the user when answer 'dont show the modification dialog' self.ask_if_externally_modified = True self.lineNumberArea = self.LineNumberArea(self) self.viewport().installEventFilter(self) self.highlighter = None styles.set_style(self, 'editor') self.connect(self, SIGNAL("cursorPositionChanged()"), self.highlight_current_line) self.connect(self, SIGNAL("modificationChanged(bool)"), self.modif_changed) self.highlight_current_line() def set_path(self, fileName): super(Editor, self).set_path(fileName) self.newDocument = False self._mtime = manage_files.get_last_modification(fileName) def check_external_modification(self): if self.newDocument: return False #Saved document we can ask for modification! return manage_files.check_for_external_modification(self.path, self._mtime) def has_write_permission(self): if self.newDocument: return True return manage_files.has_write_prmission(self.path) def register_syntax(self, fileName): ext = manage_files.get_file_extension(fileName)[1:] if self.highlighter is not None and \ not self.path.endswith(ext): self.highlighter.deleteLater() if not self.path.endswith(ext): if ext in loader.extensions: self.highlighter = Highlighter(self.document(), loader.extensions.get(ext, 'py')) else: try: self.highlighter = HighlighterPygments(self.document(), fileName) except: print 'There is no lexer for this file' #for apply rehighlighting (rehighlighting form highlighter not responding) self.firstVisibleBlock().document().find('\n').insertText('') def set_font(self, font): self.document().setDefaultFont(font) self.font_family = str(font.family()) self.font_size = font.pointSize() self.parent.notify_font_change() def set_default_font(self): #Set Font and FontSize font = QFont(self.font_family, self.font_size) self.document().setDefaultFont(font) def get_font(self): return self.document().defaultFont() def get_text(self): return self.toPlainText() def modif_changed(self, val): if self.parent is not None: self.parent.mark_as_changed(val) def zoom_in(self): font = self.font() size = font.pointSize() if size < self.font_max_size: size += 2 font.setPointSize(size) self.setFont(font) def zoom_out(self): font = self.font() size = font.pointSize() if size > self.font_min_size: size -= 2 font.setPointSize(size) self.setFont(font) def comment(self): lang = manage_files.get_file_extension(self.get_path())[1:] key = loader.extensions.get(lang, 'python') comment_wildcard = loader.syntax[key]['comment'][0] #cursor is a COPY all changes do not affect the QPlainTextEdit's cursor!!! cursor = self.textCursor() start = self.document().findBlock(cursor.selectionStart()).firstLineNumber() end = self.document().findBlock(cursor.selectionEnd()).firstLineNumber() startPosition = self.document().findBlockByLineNumber(start).position() #Start a undo block cursor.beginEditBlock() #Move the COPY cursor cursor.setPosition(startPosition) #Move the QPlainTextEdit Cursor where the COPY cursor IS! self.setTextCursor(cursor) self.moveCursor(QTextCursor.StartOfLine) self.moveCursor(QTextCursor.Right, QTextCursor.KeepAnchor) text = self.textCursor().selectedText() if text == comment_wildcard: cursor.endEditBlock() self.uncomment(start, end, startPosition) return else: self.moveCursor(QTextCursor.StartOfLine) for i in xrange(start, end+1): self.textCursor().insertText(comment_wildcard) self.moveCursor(QTextCursor.Down) self.moveCursor(QTextCursor.StartOfLine) #End a undo block cursor.endEditBlock() def uncomment(self, start=-1, end=-1, startPosition=-1): lang = manage_files.get_file_extension(self.get_path())[1:] key = loader.extensions.get(lang, 'python') comment_wildcard = loader.syntax[key]['comment'][0] #cursor is a COPY all changes do not affect the QPlainTextEdit's cursor!!! cursor = self.textCursor() if start == -1 and end == -1 and startPosition == -1: start = self.document().findBlock(cursor.selectionStart()).firstLineNumber() end = self.document().findBlock(cursor.selectionEnd()).firstLineNumber() startPosition = self.document().findBlockByLineNumber(start).position() #Start a undo block cursor.beginEditBlock() #Move the COPY cursor cursor.setPosition(startPosition) #Move the QPlainTextEdit Cursor where the COPY cursor IS! self.setTextCursor(cursor) self.moveCursor(QTextCursor.StartOfLine) for i in xrange(start, end+1): self.moveCursor(QTextCursor.Right, QTextCursor.KeepAnchor) text = self.textCursor().selectedText() if text == comment_wildcard: self.textCursor().removeSelectedText() elif u'\u2029' in text: #\u2029 is the unicode char for \n #if there is a newline, rollback the selection made above. self.moveCursor(QTextCursor.Left, QTextCursor.KeepAnchor) self.moveCursor(QTextCursor.Down) self.moveCursor(QTextCursor.StartOfLine) #End a undo block cursor.endEditBlock() def insert_horizontal_line(self): self.moveCursor(QTextCursor.StartOfLine, QTextCursor.KeepAnchor) text = unicode(self.textCursor().selection().toPlainText()) self.moveCursor(QTextCursor.EndOfLine, QTextCursor.MoveAnchor) comment = '#' * (80 - len(text)) self.textCursor().insertText(comment) def indent_more(self): #cursor is a COPY all changes do not affect the QPlainTextEdit's cursor!!! cursor = self.textCursor() selectionStart = cursor.selectionStart() selectionEnd = cursor.selectionEnd() #line where indent_more should start and end start = self.document().findBlock(cursor.selectionStart()).firstLineNumber() end = self.document().findBlock(cursor.selectionEnd()).firstLineNumber() startPosition = self.document().findBlockByLineNumber(start).position() #Start a undo block cursor.beginEditBlock() #Decide which lines will be indented cursor.setPosition(selectionEnd) self.setTextCursor(cursor) #Select one char at left #If there is a newline \u2029 (\n) then skip it self.moveCursor(QTextCursor.Left, QTextCursor.KeepAnchor) if u'\u2029' in self.textCursor().selectedText(): end -= 1 cursor.setPosition(selectionStart) self.setTextCursor(cursor) self.moveCursor(QTextCursor.StartOfLine) #Indent loop; line by line for i in xrange(start, end+1): self.textCursor().insertText(' '*Editor.indent) self.moveCursor(QTextCursor.Down, QTextCursor.MoveAnchor) #Restore the user selection cursor.setPosition(startPosition) selectionEnd = selectionEnd + (EditorGeneric.indent*(end-start+1)) cursor.setPosition(selectionEnd, QTextCursor.KeepAnchor) self.setTextCursor(cursor) #End a undo block cursor.endEditBlock() def indent_less(self): #save the total of movements made after indent_less totalIndent = 0 #cursor is a COPY all changes do not affect the QPlainTextEdit's cursor!!! cursor = self.textCursor() selectionEnd = cursor.selectionEnd() #line where indent_less should start and end start = self.document().findBlock(cursor.selectionStart()).firstLineNumber() end = self.document().findBlock(cursor.selectionEnd()).firstLineNumber() startPosition = self.document().findBlockByLineNumber(start).position() #Start a undo block cursor.beginEditBlock() #Decide which lines will be indented_less cursor.setPosition(selectionEnd) self.setTextCursor(cursor) #Select one char at left self.moveCursor(QTextCursor.Left, QTextCursor.KeepAnchor) #If there is a newline \u2029 (\n) then dont indent this line; skip it! if u'\u2029' in self.textCursor().selectedText(): end -= 1 cursor.setPosition(startPosition) self.setTextCursor(cursor) self.moveCursor(QTextCursor.StartOfLine) #Indent_less loop; line by line for i in xrange(start, end+1): #Select EditorGeneric.indent chars from the current line for j in xrange(EditorGeneric.indent): self.moveCursor(QTextCursor.Right, QTextCursor.KeepAnchor) text = self.textCursor().selectedText() if text == ' '*EditorGeneric.indent: self.textCursor().removeSelectedText() totalIndent += EditorGeneric.indent elif u'\u2029' in text: #\u2029 is the unicode char for \n #if there is a newline, rollback the selection made above. for j in xrange(EditorGeneric.indent): self.moveCursor(QTextCursor.Left, QTextCursor.KeepAnchor) #Go Down to the next line! self.moveCursor(QTextCursor.Down) #Restore the user selection cursor.setPosition(startPosition) cursor.setPosition(selectionEnd-totalIndent, QTextCursor.KeepAnchor) self.setTextCursor(cursor) #End a undo block cursor.endEditBlock() def find_match(self, word, back=False, sensitive=False, whole=False): b = QTextDocument.FindBackward if back else None s = QTextDocument.FindCaseSensitively if sensitive else None w = QTextDocument.FindWholeWords if whole else None self.moveCursor(QTextCursor.NoMove, QTextCursor.KeepAnchor) if back or sensitive or whole: self.find(word, b or s or w) else: self.find(word) def replace_match(self, wordOld, wordNew, sensitive=False, whole=False, all=False): s = QTextDocument.FindCaseSensitively if sensitive else None w = QTextDocument.FindWholeWords if whole else None self.moveCursor(QTextCursor.NoMove, QTextCursor.KeepAnchor) cursor = self.textCursor() cursor.beginEditBlock() self.moveCursor(QTextCursor.Start) replace = True while (replace or all): result = False if back or sensitive or whole: result = self.find(wordOld, s or w) else: result = self.find(wordOld) if result: tc = self.textCursor() if tc.hasSelection(): tc.insertText(wordNew) else: break replace = False cursor.endEditBlock() def highlight_current_line(self): extraSelections = [] if not self.isReadOnly(): selection = QTextEdit.ExtraSelection() lineColor = QColor(Qt.darkCyan) lineColor.setAlpha(20) selection.format.setBackground(lineColor) selection.format.setProperty(QTextFormat.FullWidthSelection, True) selection.cursor = self.textCursor() selection.cursor.clearSelection() extraSelections.append(selection) self.setExtraSelections(extraSelections) def resizeEvent(self,e): self.lineNumberArea.setFixedHeight(self.height()) QPlainTextEdit.resizeEvent(self,e) def eventFilter(self, object, event): if object is self.viewport(): self.lineNumberArea.update() return False return QPlainTextEdit.eventFilter(object, event) def keyPressEvent(self, event): if self.completer is not None and self.completer.popup().isVisible(): if event.key() in (Qt.Key_Enter, Qt.Key_Return, Qt.Key_Tab, Qt.Key_Escape, Qt.Key_Backtab): event.ignore() self.completer.popup().hide() return elif event.key == Qt.Key_Space: self.completer.popup().hide() if event.key() == Qt.Key_Tab: if self.textCursor().hasSelection(): self.indent_more() return else: self.textCursor().insertText(' '*EditorGeneric.indent) return elif event.key() == Qt.Key_Backspace: if self.textCursor().hasSelection(): super(Editor, self).keyPressEvent(event) return for i in xrange(EditorGeneric.indent): self.moveCursor(QTextCursor.Left, QTextCursor.KeepAnchor) text = self.textCursor().selection() if unicode(text.toPlainText()) == ' '*EditorGeneric.indent: self.textCursor().removeSelectedText() return else: for i in xrange(EditorGeneric.indent): self.moveCursor(QTextCursor.Right) elif event.key() == Qt.Key_Home: if event.modifiers() == Qt.ShiftModifier: move = QTextCursor.KeepAnchor else: move = QTextCursor.MoveAnchor if self.textCursor().atBlockStart(): self.moveCursor(QTextCursor.WordRight, move) return super(Editor, self).keyPressEvent(event) if event.key() in (Qt.Key_Enter, Qt.Key_Return): text = unicode(self.document().findBlock(self.textCursor().position()-1).text()) spaces = self.get_indentation(text) self.textCursor().insertText(spaces) if text != '' and text == ' '*len(text): previousLine = self.document().findBlock(self.textCursor().position()-1) self.moveCursor(QTextCursor.Up) self.moveCursor(QTextCursor.EndOfLine, QTextCursor.KeepAnchor) self.textCursor().removeSelectedText() self.moveCursor(QTextCursor.Down) self.eventKeyReturn() elif unicode(event.text()) in self.braces_strings: self.textCursor().insertText(self.braces_strings[str(event.text())]) self.moveCursor(QTextCursor.Left) completionPrefix = self.text_under_cursor() if event.key() == Qt.Key_Period or \ (event.key() == Qt.Key_Space and event.modifiers() == Qt.ControlModifier): self.completer.setCompletionPrefix('') cr = self.cursorRect() self.completer.complete(cr) if self.completer is not None and self.completer.popup().isVisible(): if completionPrefix != self.completer.completionPrefix(): self.completer.setCompletionPrefix(completionPrefix) self.completer.popup().setCurrentIndex(self.completer.completionModel().index(0, 0)) self.completer.setCurrentRow(0) cr = self.cursorRect() self.completer.complete(cr) self.eventKeyAny() def text_under_cursor(self): tc = self.textCursor() tc.select(QTextCursor.WordUnderCursor) return tc.selectedText() def wheelEvent(self, event): if event.modifiers() == Qt.ControlModifier: if event.delta() == 120: self.zoom_in() elif event.delta() == -120: self.zoom_out() event.ignore() else: super(Editor, self).wheelEvent(event) def focusInEvent(self, event): super(Editor, self).focusInEvent(event) self.parent.editor_focus() def dropEvent(self, event): if event.mimeData().hasText(): fileName = str(event.mimeData().text())[7:].rstrip() content = manage_files.read_file_content(fileName) self.setPlainText(content) def contextMenuEvent(self, event): popup_menu = self.createStandardContextMenu() lang = manage_files.get_file_extension(self.get_path())[1:] if EditorGeneric.extraMenus.get(lang, False): popup_menu.insertSeparator(popup_menu.actions()[0]) popup_menu.insertMenu(popup_menu.actions()[0], EditorGeneric.extraMenus[lang]) popup_menu.exec_(event.globalPos()) #based on: http://john.nachtimwald.com/2009/08/15/qtextedit-with-line-numbers/ (MIT license) class LineNumberArea(QWidget): def __init__(self, editor): QWidget.__init__(self, editor) self.edit = editor self.highest_line = 0 css = ''' QWidget { font-family: monospace; font-size: 10; color: black; }''' self.setStyleSheet(css) def update(self, *args): width = QFontMetrics(self.edit.document().defaultFont()).width(str(self.highest_line)) + 10 if self.width() != width: self.setFixedWidth(width) self.edit.setViewportMargins(width,0,0,0) QWidget.update(self, *args) def paintEvent(self, event): contents_y = 0 page_bottom = self.edit.viewport().height() font_metrics = QFontMetrics(self.edit.document().defaultFont()) current_block = self.edit.document().findBlock(self.edit.textCursor().position()) painter = QPainter(self) painter.fillRect(self.rect(), Qt.lightGray) block = self.edit.firstVisibleBlock() viewport_offset = self.edit.contentOffset() line_count = block.blockNumber() painter.setFont(self.edit.document().defaultFont()) while block.isValid(): line_count += 1 # The top left position of the block in the document position = self.edit.blockBoundingGeometry(block).topLeft() + viewport_offset # Check if the position of the block is out side of the visible area if position.y() > page_bottom: break # We want the line number for the selected line to be bold. bold = False if block == current_block: bold = True font = painter.font() font.setBold(True) painter.setFont(font) # Draw the line number right justified at the y position of the # line. 3 is a magic padding number. drawText(x, y, text). painter.drawText(self.width() - font_metrics.width(str(line_count)) - 3, round(position.y()) + font_metrics.ascent()+font_metrics.descent()-1, str(line_count)) # Remove the bold style if it was set previously. if bold: font = painter.font() font.setBold(False) painter.setFont(font) block = block.next() self.highest_line = line_count painter.end() QWidget.paintEvent(self, event)
class Interpreter(InteractiveInterpreter): def __init__(self, namespace=None): if namespace is not None: namespace = namespace() InteractiveInterpreter.__init__(self, namespace) self.output_trap = OutputTrap() self.completer = Completer(self.locals) self.input_count = 0 self.interrupted = False def _result_dict(self, out, in_string="", err="", in_count="", cmd_count=""): return {"input_count": in_count, "cmd_count": cmd_count, "in": in_string, "out": out, "err": err} # ------------------------------------------------ # Main methods to call external # def cancel_interrupt(self): self.interrupted = False return self._result_dict("ok") def evaluate(self, input_string): """give the input_string to the python interpreter in the usernamespace""" self.output_trap.set() command_count = self._runcommands(input_string) out_values = self.output_trap.get_values() self.output_trap.reset() self.input_count += 1 result = { "input_count": self.input_count, "cmd_count": command_count, "in": input_string, "out": out_values[0], "err": out_values[1], } return result def introspect(self, input_string): """See what information there is about this objects methods and attributes.""" info = introspect(input_string) def complete_name(self, input_string): """See what possible completions there are for this object (input_string).""" matches = self.completer.global_matches(input_string) # return ' '.join(matches) return matches def complete_attr(self, input_string): matches = self.completer.attr_matches(input_string) return matches # # ----------------------------------------------- def _runcommands(self, input_string): """input_string could contain multiple lines, multiple commands, or multiple multiline commands. This method builds a compiled command line by line until a complete command has been compiled. Once it has a complete command, it execs it in the username space and the output is stored in the output trap. There may be more than one command; the number of complete commands is counted (Based off of ipython1.core.shell.InteractiveShell._runlines)""" command_buffer = [] command_count = 0 if self.interrupted: print >>sys.stderr, "Aborted." # sys.stderr.write('Aborted') return command_count lines = input_string.split("\n") lines = [l for l in lines if len(l) > 0] more = False for line in lines: line = self._pre_execute_filter(line) command_buffer.append(line) if line or more: torun = "\n".join(command_buffer) try: more = self.runsource(torun) except OperationAborted, e: print >>sys.stderr, e.value # sys.stderr.write(e.value) # XXX This could be bad if something other than the # kernelConnection triggers an interrupt self.interrupted = True return command_count if more: pass else: command_buffer = [] command_count += 1 more = False if more: command_buffer.append("\n") torun = "\n".join(command_buffer) more = self.runsource(torun) return command_count
class Interpreter(InteractiveInterpreter): def __init__(self, namespace=None): if namespace is not None: namespace = namespace() InteractiveInterpreter.__init__(self, namespace) self.output_trap = OutputTrap() self.completer = Completer(self.locals) self.input_count = 0 self.interrupted = False def _result_dict(self, out, in_string='', err='', in_count='', cmd_count=''): return { 'input_count': in_count, 'cmd_count': cmd_count, 'in': in_string, 'out': out, 'err': err } #------------------------------------------------ # Main methods to call external # def cancel_interrupt(self): self.interrupted = False return self._result_dict('ok') def evaluate(self, input_string): """give the input_string to the python interpreter in the usernamespace""" self.output_trap.set() command_count = self._runcommands(input_string) out_values = self.output_trap.get_values() self.output_trap.reset() self.input_count += 1 result = { 'input_count': self.input_count, 'cmd_count': command_count, 'in': input_string, 'out': out_values[0], 'err': out_values[1] } return result def introspect(self, input_string): """See what information there is about this objects methods and attributes.""" info = introspect(input_string) def complete(self, input_string): """ Complete a name or attribute. """ reName = "([a-zA-Z_][a-zA-Z_0-9]*)$" reAttribute = "([a-zA-Z_][a-zA-Z_0-9]*[.]+[a-zA-Z_.0-9]*)$" nameMatch = re.match(reName, input_string) attMatch = re.match(reAttribute, input_string) if nameMatch: matches = self.completer.global_matches(input_string) return {'out': matches} if attMatch: matches = self.completer.attr_matches(input_string) return {'out': matches} return {'out': []} def complete_name(self, input_string): """See what possible completions there are for this object (input_string).""" matches = self.completer.global_matches(input_string) # return ' '.join(matches) return matches def complete_attr(self, input_string): matches = self.completer.attr_matches(input_string) return matches # #----------------------------------------------- def _runcommands(self, input_string): """input_string could contain multiple lines, multiple commands, or multiple multiline commands. This method builds a compiled command line by line until a complete command has been compiled. Once it has a complete command, it execs it in the username space and the output is stored in the output trap. There may be more than one command; the number of complete commands is counted (Based off of ipython1.core.shell.InteractiveShell._runlines)""" command_buffer = [] command_count = 0 if self.interrupted: print >> sys.stderr, 'Aborted.' #sys.stderr.write('Aborted') return command_count lines = input_string.split('\n') lines = [l for l in lines if len(l) > 0] more = False for line in lines: line = self._pre_execute_filter(line) command_buffer.append(line) if line or more: torun = '\n'.join(command_buffer) try: more = self.runsource(torun) except OperationAborted, e: print >> sys.stderr, e.value #sys.stderr.write(e.value) # XXX This could be bad if something other than the # kernelConnection triggers an interrupt #self.interrupted = True return command_count if more: pass else: command_buffer = [] command_count += 1 more = False if more: command_buffer.append('\n') torun = '\n'.join(command_buffer) more = self.runsource(torun) return command_count
class Editor(QPlainTextEdit, EditorGeneric, BaseCentralWidget): def __init__(self, parent, project=None): QPlainTextEdit.__init__(self) EditorGeneric.__init__(self) BaseCentralWidget.__init__(self) self.parent = parent self.completer = Completer(self, project) self.setWordWrapMode(QTextOption.NoWrap) doc = self.document() option = QTextOption() option.setFlags(QTextOption.ShowTabsAndSpaces) doc.setDefaultTextOption(option) self.setDocument(doc) self.set_default_font() #file modification time POSIX self._mtime = None #Flag to dont bug the user when answer 'dont show the modification dialog' self.ask_if_externally_modified = True self.lineNumberArea = self.LineNumberArea(self) self.viewport().installEventFilter(self) self.highlighter = None styles.set_style(self, 'editor') self.connect(self, SIGNAL("cursorPositionChanged()"), self.highlight_current_line) self.connect(self, SIGNAL("modificationChanged(bool)"), self.modif_changed) self.highlight_current_line() def set_path(self, fileName): super(Editor, self).set_path(fileName) self.newDocument = False self._mtime = manage_files.get_last_modification(fileName) def check_external_modification(self): if self.newDocument: return False #Saved document we can ask for modification! return manage_files.check_for_external_modification( self.path, self._mtime) def has_write_permission(self): if self.newDocument: return True return manage_files.has_write_prmission(self.path) def register_syntax(self, fileName): ext = manage_files.get_file_extension(fileName)[1:] if self.highlighter is not None and \ not self.path.endswith(ext): self.highlighter.deleteLater() if not self.path.endswith(ext): if ext in loader.extensions: self.highlighter = Highlighter( self.document(), loader.extensions.get(ext, 'py')) else: try: self.highlighter = HighlighterPygments( self.document(), fileName) except: print 'There is no lexer for this file' #for apply rehighlighting (rehighlighting form highlighter not responding) self.firstVisibleBlock().document().find('\n').insertText('') def set_font(self, font): self.document().setDefaultFont(font) self.font_family = str(font.family()) self.font_size = font.pointSize() self.parent.notify_font_change() def set_default_font(self): #Set Font and FontSize font = QFont(self.font_family, self.font_size) self.document().setDefaultFont(font) def get_font(self): return self.document().defaultFont() def get_text(self): return self.toPlainText() def modif_changed(self, val): if self.parent is not None: self.parent.mark_as_changed(val) def zoom_in(self): font = self.font() size = font.pointSize() if size < self.font_max_size: size += 2 font.setPointSize(size) self.setFont(font) def zoom_out(self): font = self.font() size = font.pointSize() if size > self.font_min_size: size -= 2 font.setPointSize(size) self.setFont(font) def comment(self): lang = manage_files.get_file_extension(self.get_path())[1:] key = loader.extensions.get(lang, 'python') comment_wildcard = loader.syntax[key]['comment'][0] #cursor is a COPY all changes do not affect the QPlainTextEdit's cursor!!! cursor = self.textCursor() start = self.document().findBlock( cursor.selectionStart()).firstLineNumber() end = self.document().findBlock( cursor.selectionEnd()).firstLineNumber() startPosition = self.document().findBlockByLineNumber(start).position() #Start a undo block cursor.beginEditBlock() #Move the COPY cursor cursor.setPosition(startPosition) #Move the QPlainTextEdit Cursor where the COPY cursor IS! self.setTextCursor(cursor) self.moveCursor(QTextCursor.StartOfLine) self.moveCursor(QTextCursor.Right, QTextCursor.KeepAnchor) text = self.textCursor().selectedText() if text == comment_wildcard: cursor.endEditBlock() self.uncomment(start, end, startPosition) return else: self.moveCursor(QTextCursor.StartOfLine) for i in xrange(start, end + 1): self.textCursor().insertText(comment_wildcard) self.moveCursor(QTextCursor.Down) self.moveCursor(QTextCursor.StartOfLine) #End a undo block cursor.endEditBlock() def uncomment(self, start=-1, end=-1, startPosition=-1): lang = manage_files.get_file_extension(self.get_path())[1:] key = loader.extensions.get(lang, 'python') comment_wildcard = loader.syntax[key]['comment'][0] #cursor is a COPY all changes do not affect the QPlainTextEdit's cursor!!! cursor = self.textCursor() if start == -1 and end == -1 and startPosition == -1: start = self.document().findBlock( cursor.selectionStart()).firstLineNumber() end = self.document().findBlock( cursor.selectionEnd()).firstLineNumber() startPosition = self.document().findBlockByLineNumber( start).position() #Start a undo block cursor.beginEditBlock() #Move the COPY cursor cursor.setPosition(startPosition) #Move the QPlainTextEdit Cursor where the COPY cursor IS! self.setTextCursor(cursor) self.moveCursor(QTextCursor.StartOfLine) for i in xrange(start, end + 1): self.moveCursor(QTextCursor.Right, QTextCursor.KeepAnchor) text = self.textCursor().selectedText() if text == comment_wildcard: self.textCursor().removeSelectedText() elif u'\u2029' in text: #\u2029 is the unicode char for \n #if there is a newline, rollback the selection made above. self.moveCursor(QTextCursor.Left, QTextCursor.KeepAnchor) self.moveCursor(QTextCursor.Down) self.moveCursor(QTextCursor.StartOfLine) #End a undo block cursor.endEditBlock() def insert_horizontal_line(self): self.moveCursor(QTextCursor.StartOfLine, QTextCursor.KeepAnchor) text = unicode(self.textCursor().selection().toPlainText()) self.moveCursor(QTextCursor.EndOfLine, QTextCursor.MoveAnchor) comment = '#' * (80 - len(text)) self.textCursor().insertText(comment) def indent_more(self): #cursor is a COPY all changes do not affect the QPlainTextEdit's cursor!!! cursor = self.textCursor() selectionStart = cursor.selectionStart() selectionEnd = cursor.selectionEnd() #line where indent_more should start and end start = self.document().findBlock( cursor.selectionStart()).firstLineNumber() end = self.document().findBlock( cursor.selectionEnd()).firstLineNumber() startPosition = self.document().findBlockByLineNumber(start).position() #Start a undo block cursor.beginEditBlock() #Decide which lines will be indented cursor.setPosition(selectionEnd) self.setTextCursor(cursor) #Select one char at left #If there is a newline \u2029 (\n) then skip it self.moveCursor(QTextCursor.Left, QTextCursor.KeepAnchor) if u'\u2029' in self.textCursor().selectedText(): end -= 1 cursor.setPosition(selectionStart) self.setTextCursor(cursor) self.moveCursor(QTextCursor.StartOfLine) #Indent loop; line by line for i in xrange(start, end + 1): self.textCursor().insertText(' ' * Editor.indent) self.moveCursor(QTextCursor.Down, QTextCursor.MoveAnchor) #Restore the user selection cursor.setPosition(startPosition) selectionEnd = selectionEnd + (EditorGeneric.indent * (end - start + 1)) cursor.setPosition(selectionEnd, QTextCursor.KeepAnchor) self.setTextCursor(cursor) #End a undo block cursor.endEditBlock() def indent_less(self): #save the total of movements made after indent_less totalIndent = 0 #cursor is a COPY all changes do not affect the QPlainTextEdit's cursor!!! cursor = self.textCursor() selectionEnd = cursor.selectionEnd() #line where indent_less should start and end start = self.document().findBlock( cursor.selectionStart()).firstLineNumber() end = self.document().findBlock( cursor.selectionEnd()).firstLineNumber() startPosition = self.document().findBlockByLineNumber(start).position() #Start a undo block cursor.beginEditBlock() #Decide which lines will be indented_less cursor.setPosition(selectionEnd) self.setTextCursor(cursor) #Select one char at left self.moveCursor(QTextCursor.Left, QTextCursor.KeepAnchor) #If there is a newline \u2029 (\n) then dont indent this line; skip it! if u'\u2029' in self.textCursor().selectedText(): end -= 1 cursor.setPosition(startPosition) self.setTextCursor(cursor) self.moveCursor(QTextCursor.StartOfLine) #Indent_less loop; line by line for i in xrange(start, end + 1): #Select EditorGeneric.indent chars from the current line for j in xrange(EditorGeneric.indent): self.moveCursor(QTextCursor.Right, QTextCursor.KeepAnchor) text = self.textCursor().selectedText() if text == ' ' * EditorGeneric.indent: self.textCursor().removeSelectedText() totalIndent += EditorGeneric.indent elif u'\u2029' in text: #\u2029 is the unicode char for \n #if there is a newline, rollback the selection made above. for j in xrange(EditorGeneric.indent): self.moveCursor(QTextCursor.Left, QTextCursor.KeepAnchor) #Go Down to the next line! self.moveCursor(QTextCursor.Down) #Restore the user selection cursor.setPosition(startPosition) cursor.setPosition(selectionEnd - totalIndent, QTextCursor.KeepAnchor) self.setTextCursor(cursor) #End a undo block cursor.endEditBlock() def find_match(self, word, back=False, sensitive=False, whole=False): b = QTextDocument.FindBackward if back else None s = QTextDocument.FindCaseSensitively if sensitive else None w = QTextDocument.FindWholeWords if whole else None self.moveCursor(QTextCursor.NoMove, QTextCursor.KeepAnchor) if back or sensitive or whole: self.find(word, b or s or w) else: self.find(word) def replace_match(self, wordOld, wordNew, sensitive=False, whole=False, all=False): s = QTextDocument.FindCaseSensitively if sensitive else None w = QTextDocument.FindWholeWords if whole else None self.moveCursor(QTextCursor.NoMove, QTextCursor.KeepAnchor) cursor = self.textCursor() cursor.beginEditBlock() self.moveCursor(QTextCursor.Start) replace = True while (replace or all): result = False if back or sensitive or whole: result = self.find(wordOld, s or w) else: result = self.find(wordOld) if result: tc = self.textCursor() if tc.hasSelection(): tc.insertText(wordNew) else: break replace = False cursor.endEditBlock() def highlight_current_line(self): extraSelections = [] if not self.isReadOnly(): selection = QTextEdit.ExtraSelection() lineColor = QColor(Qt.darkCyan) lineColor.setAlpha(20) selection.format.setBackground(lineColor) selection.format.setProperty(QTextFormat.FullWidthSelection, True) selection.cursor = self.textCursor() selection.cursor.clearSelection() extraSelections.append(selection) self.setExtraSelections(extraSelections) def resizeEvent(self, e): self.lineNumberArea.setFixedHeight(self.height()) QPlainTextEdit.resizeEvent(self, e) def eventFilter(self, object, event): if object is self.viewport(): self.lineNumberArea.update() return False return QPlainTextEdit.eventFilter(object, event) def keyPressEvent(self, event): if self.completer is not None and self.completer.popup().isVisible(): if event.key() in (Qt.Key_Enter, Qt.Key_Return, Qt.Key_Tab, Qt.Key_Escape, Qt.Key_Backtab): event.ignore() self.completer.popup().hide() return elif event.key == Qt.Key_Space: self.completer.popup().hide() if event.key() == Qt.Key_Tab: if self.textCursor().hasSelection(): self.indent_more() return else: self.textCursor().insertText(' ' * EditorGeneric.indent) return elif event.key() == Qt.Key_Backspace: if self.textCursor().hasSelection(): super(Editor, self).keyPressEvent(event) return for i in xrange(EditorGeneric.indent): self.moveCursor(QTextCursor.Left, QTextCursor.KeepAnchor) text = self.textCursor().selection() if unicode(text.toPlainText()) == ' ' * EditorGeneric.indent: self.textCursor().removeSelectedText() return else: for i in xrange(EditorGeneric.indent): self.moveCursor(QTextCursor.Right) elif event.key() == Qt.Key_Home: if event.modifiers() == Qt.ShiftModifier: move = QTextCursor.KeepAnchor else: move = QTextCursor.MoveAnchor if self.textCursor().atBlockStart(): self.moveCursor(QTextCursor.WordRight, move) return super(Editor, self).keyPressEvent(event) if event.key() in (Qt.Key_Enter, Qt.Key_Return): text = unicode( self.document().findBlock(self.textCursor().position() - 1).text()) spaces = self.get_indentation(text) self.textCursor().insertText(spaces) if text != '' and text == ' ' * len(text): previousLine = self.document().findBlock( self.textCursor().position() - 1) self.moveCursor(QTextCursor.Up) self.moveCursor(QTextCursor.EndOfLine, QTextCursor.KeepAnchor) self.textCursor().removeSelectedText() self.moveCursor(QTextCursor.Down) self.eventKeyReturn() elif unicode(event.text()) in self.braces_strings: self.textCursor().insertText(self.braces_strings[str( event.text())]) self.moveCursor(QTextCursor.Left) completionPrefix = self.text_under_cursor() if event.key() == Qt.Key_Period or \ (event.key() == Qt.Key_Space and event.modifiers() == Qt.ControlModifier): self.completer.setCompletionPrefix('') cr = self.cursorRect() self.completer.complete(cr) if self.completer is not None and self.completer.popup().isVisible(): if completionPrefix != self.completer.completionPrefix(): self.completer.setCompletionPrefix(completionPrefix) self.completer.popup().setCurrentIndex( self.completer.completionModel().index(0, 0)) self.completer.setCurrentRow(0) cr = self.cursorRect() self.completer.complete(cr) self.eventKeyAny() def text_under_cursor(self): tc = self.textCursor() tc.select(QTextCursor.WordUnderCursor) return tc.selectedText() def wheelEvent(self, event): if event.modifiers() == Qt.ControlModifier: if event.delta() == 120: self.zoom_in() elif event.delta() == -120: self.zoom_out() event.ignore() else: super(Editor, self).wheelEvent(event) def focusInEvent(self, event): super(Editor, self).focusInEvent(event) self.parent.editor_focus() def dropEvent(self, event): if event.mimeData().hasText(): fileName = str(event.mimeData().text())[7:].rstrip() content = manage_files.read_file_content(fileName) self.setPlainText(content) def contextMenuEvent(self, event): popup_menu = self.createStandardContextMenu() lang = manage_files.get_file_extension(self.get_path())[1:] if EditorGeneric.extraMenus.get(lang, False): popup_menu.insertSeparator(popup_menu.actions()[0]) popup_menu.insertMenu(popup_menu.actions()[0], EditorGeneric.extraMenus[lang]) popup_menu.exec_(event.globalPos()) #based on: http://john.nachtimwald.com/2009/08/15/qtextedit-with-line-numbers/ (MIT license) class LineNumberArea(QWidget): def __init__(self, editor): QWidget.__init__(self, editor) self.edit = editor self.highest_line = 0 css = ''' QWidget { font-family: monospace; font-size: 10; color: black; }''' self.setStyleSheet(css) def update(self, *args): width = QFontMetrics(self.edit.document().defaultFont()).width( str(self.highest_line)) + 10 if self.width() != width: self.setFixedWidth(width) self.edit.setViewportMargins(width, 0, 0, 0) QWidget.update(self, *args) def paintEvent(self, event): contents_y = 0 page_bottom = self.edit.viewport().height() font_metrics = QFontMetrics(self.edit.document().defaultFont()) current_block = self.edit.document().findBlock( self.edit.textCursor().position()) painter = QPainter(self) painter.fillRect(self.rect(), Qt.lightGray) block = self.edit.firstVisibleBlock() viewport_offset = self.edit.contentOffset() line_count = block.blockNumber() painter.setFont(self.edit.document().defaultFont()) while block.isValid(): line_count += 1 # The top left position of the block in the document position = self.edit.blockBoundingGeometry( block).topLeft() + viewport_offset # Check if the position of the block is out side of the visible area if position.y() > page_bottom: break # We want the line number for the selected line to be bold. bold = False if block == current_block: bold = True font = painter.font() font.setBold(True) painter.setFont(font) # Draw the line number right justified at the y position of the # line. 3 is a magic padding number. drawText(x, y, text). painter.drawText( self.width() - font_metrics.width(str(line_count)) - 3, round(position.y()) + font_metrics.ascent() + font_metrics.descent() - 1, str(line_count)) # Remove the bold style if it was set previously. if bold: font = painter.font() font.setBold(False) painter.setFont(font) block = block.next() self.highest_line = line_count painter.end() QWidget.paintEvent(self, event)
class Console(InteractiveConsole): def __init__(self, locals = __builtin__.globals()): InteractiveConsole.__init__(self, locals) self.stdout = sys.stdout self.stderr = sys.stderr self.pipe = Pipe() self.completer = Completer(locals) #------------------------------------------------------------------------------- def redirectOutput(self, stdout, stderr): sys.stdout = stdout sys.stderr = stderr #------------------------------------------------------------------------------- def push(self, input): self.redirectOutput(self.pipe, self.pipe) InteractiveConsole.push(self, input) self.redirectOutput(self.stdout, self.stderr) output = self.pipe.flush() return output #------------------------------------------------------------------------------- def complete(self, input): completed = input candidates = [] words = input.split(" ") matches = self.completer.getMatches(words[-1]) for match in matches: if callable(matches[match]): candidates.append(match+"()") else: candidates.append(match) if len(matches) == 1: match = matches.iterkeys().next() words = words[0:-1] words.append(match) completed = " ".join(words) if callable(matches[match]): completed += "(" return completed, candidates #------------------------------------------------------------------------------- def help(self, input): text = None doc = self.push("%s.__doc__" % input) if ("Traceback" in doc) or ("SyntaxError" in doc): doc = None self.push("import inspect") src = self.push("inspect.getsourcelines(%s)[0][0:6]" % input) if ("Traceback" in src) or ("SyntaxError" in src): src = None if doc: exec("text = ''.join(%s)" % doc) elif src: exec("text = ''.join(%s)" % src) if text: text = text.strip(os.linesep) return text
readline.read_history_file(history_file) except IOError: pass import atexit atexit.register(readline.write_history_file, history_file) del history_file del atexit del path, environ # Establish client. # cicada = Client(host = 'bee2') cicada = Client() completer = Completer() # Set the command prompt def set_prompt(prompt, sentinel = '>', spacer = True): sys.ps1 = prompt + sentinel sys.ps2 = '' for c in sys.ps1: sys.ps2 += '.' if spacer: sys.ps1 += ' ' sys.ps2 += ' ' # This may ignore useful completion items; unignore or use unregister instead. completer.ignore(globals())