def runDebugScriptCommand(self, event=None): """Called when user presses the 'debug-script' button or executes the debug-script command.""" c = self.c p = c.p script = g.getScript(c, p, useSelectedText=True, useSentinels=False) if script: # @+<< set debugging if debugger is active >> # @+node:ekr.20060523084441: *6* << set debugging if debugger is active >> g.trace(self.debuggerKind) if self.debuggerKind == "winpdb": try: import rpdb2 debugging = rpdb2.g_debugger is not None except ImportError: debugging = False elif self.debuggerKind == "idle": # import idlelib.Debugger.py as Debugger # debugging = Debugger.interacting debugging = True else: debugging = False # @-<< set debugging if debugger is active >> if debugging: # @+<< create leoScriptModule >> # @+node:ekr.20060524073716: *6* << create leoScriptModule >> target = g.os_path_join(g.app.loadDir, "leoScriptModule.py") f = None try: f = file(target, "w") f.write("# A module holding the script to be debugged.\n") if self.debuggerKind == "idle": # This works, but uses the lame pdb debugger. f.write("import pdb\n") f.write("pdb.set_trace() # Hard breakpoint.\n") elif self.debuggerKind == "winpdb": f.write("import rpdb2\n") f.write("if rpdb2.g_debugger is not None: # don't hang if the debugger isn't running.\n") f.write(' rpdb2.start_embedded_debugger(pwd="",fAllowUnencrypted=True) # Hard breakpoint.\n') # f.write('# Remove all previous variables.\n') f.write("# Predefine c, g and p.\n") f.write("import leo.core.leoGlobals as g\n") f.write('c = g.app.scriptDict.get("c")\n') f.write("p = c.p\n") f.write("# Actual script starts here.\n") f.write(script + "\n") finally: if f: f.close() # @-<< create leoScriptModule >> # pylint: disable=E0611 # E0611:runDebugScriptCommand: No name 'leoScriptModule' in module 'leo.core' g.app.scriptDict["c"] = c if "leoScriptModule" in sys.modules.keys(): del sys.modules["leoScriptModule"] # Essential. import leo.core.leoScriptModule as leoScriptModule else: g.error("No debugger active") c.bodyWantsFocus()
def getIDFromFile(self): '''Attempt to set g.app.leoID from leoID.txt.''' g = self.g trace = False and not g.app.silentMode tag = ".leoID.txt" for theDir in (g.app.homeDir, g.app.globalConfigDir, g.app.loadDir): if not theDir: continue # do *not* use the current directory! fn = g.os_path_join(theDir, tag) try: with open(fn, 'r') as f: s = f.readline().strip() if not s: continue g.app.leoID = s if trace: g.es('leoID=%r (in %s)' % (s, theDir), color='red') else: g.es('leoID=%r' % (s), color='red') except IOError: g.app.leoID = None except Exception: g.app.leoID = None g.error('unexpected exception in app.setLeoID') g.es_exception()
def shellScriptInWindow(c,script): if sys.platform == 'darwin': #@+<< write script to temporary MacOS file >> #@+node:ekr.20040915105758.22: *3* << write script to temporary MacOS file >> handle, path = tempfile.mkstemp(text=True) directory = c.frame.openDirectory script = ("cd %s\n" % directory) + script + '\n' + ("rm -f %s\n" % path) os.write(handle, script) os.close(handle) os.chmod(path,0x700) #@-<< write script to temporary MacOS file >> os.system("open -a /Applications/Utilities/Terminal.app " + path) elif sys.platform == 'win32': g.error("shellScriptInWindow not ready for Windows") else: #@+<< write script to temporary Unix file >> #@+node:ekr.20040915105758.25: *3* << write script to temporary Unix file >> handle, path = tempfile.mkstemp(text=True) directory = c.frame.openDirectory script = ("cd %s\n" % directory) + script + '\n' + ("rm -f %s\n" % path) os.write(handle, script) os.close(handle) os.chmod(path,0x700) #@-<< write script to temporary Unix file >> os.system("xterm -e sh " + path)
def error(self, s, silent=False): x = self if not silent: g.error(s) # For unit testing. x.last_error = s x.errors += 1
def OLD_parse_opml_file(self, inputFileName): if not inputFileName or not inputFileName.endswith(".opml"): return None c = self.c path = g.os_path_normpath(g.os_path_join(g.app.loadDir, inputFileName)) try: f = open(path) except IOError: g.trace("can not open %s" % path) return None try: try: node = None parser = xml.sax.make_parser() # Do not include external general entities. # The actual feature name is "http://xml.org/sax/features/external-general-entities" parser.setFeature(xml.sax.handler.feature_external_ges, 0) handler = SaxContentHandler(c, inputFileName) parser.setContentHandler(handler) parser.parse(f) node = handler.getNode() except xml.sax.SAXParseException: g.error("Error parsing %s" % (inputFileName)) g.es_exception() return None except Exception: g.error("Unexpected exception parsing %s" % (inputFileName)) g.es_exception() return None finally: f.close() return node
def dtest(self, event): """The handler for dtest """ import leo.core.leoGlobals as g # get a valid temporary filename createfile, tempfilename = g.create_temp_file() createfile.close() selected = False # if text is selected, only test selection if self.c.frame.body.hasTextSelection(): selected = True selection = self.c.frame.body.getSelectedText() tempfile = open(tempfilename, 'w') tempfile.write(selection) tempfile.close() # if no selection, test this subtree else: self.c.importCommands.flattenOutline(tempfilename) tempfile = open(tempfilename) text = tempfile.readlines() tempfile.close() # strip trailing whitespace, an annoying source of doctest failures text = [line.rstrip() for line in text] text = "\n".join(text) tempfile = open(tempfilename, 'w') tempfile.write(text) tempfile.close() import copy # build globals dictionary globals = {'c':copy.copy(self.c), 'g':g} # run doctest on temporary file failures, tests = doctest.testfile(tempfilename, module_relative = False, optionflags = doctest.ELLIPSIS, globs = globals) #@+<<report summary of results>> #@+node:ekr.20070119094733.10: *4* <<report summary of results>> if selected: g.es('Result of running doctest on selected text;') else: g.es('Result of running doctest on this subtree;') if failures == 0: g.blue("%s tests run successfully" % tests) if failures == 1: g.error("There was one failure in %s tests" % tests) if failures > 1: g.error("%s failures in %s tests" % (failures, tests)) #@-<<report summary of results>> #clean up temp file os.remove(tempfilename)
def reportChangedClone(self, child_v, b, h, gnx): trace = (False or g.app.debug) and not g.unitTesting c = self.c fileName = c.cacheListFileName old, new = child_v.b, b same = ( old == new or new.endswith('\n') and old == new[: -1] or old.endswith('\n') and new == old[: -1]) # if trace and not same: if trace and (not same or h == 'writeException'): g.trace('same %s old %s new %s %s %s' % ( same, len(old), len(new), h, fileName)) # This would make it impossible to clear nodes! # if not new: return same if same: return c.nodeConflictList.append(g.bunch( tag='(cached)', fileName=fileName, gnx=gnx, b_old=child_v.b, h_old=child_v.h, b_new=b, h_new=h, )) # Always issue the warning. g.error("cached read node changed:", child_v.h) child_v.h, child_v.b = h, b child_v.setDirty() c.changed = True # Tell getLeoFile to propegate dirty nodes.
def open_dict(self, fn, language): '''Open or create the dict with the given fn.''' trace = False and not g.unitTesting if not fn or not language: return d = g.app.spellDict if d: self.d = d if trace: g.trace('already open', self.c.fileName(), fn) return if not g.os_path_exists(fn): # Fix bug 1175013: leo/plugins/spellpyx.txt is both source controlled and customized. self.create(fn) if g.os_path_exists(fn): # Merge the local and global dictionaries. try: self.clean_dict(fn) self.d = enchant.DictWithPWL(language, fn) if trace: g.trace('open', g.shortFileName(self.c.fileName()), fn) except Exception: g.es_exception() g.error('not a valid dictionary file', fn) self.d = enchant.Dict(language) else: # A fallback. Unlikely to happen. self.d = enchant.Dict(language) # Use only a single copy of the dict. g.app.spellDict = self.d
def CloseProcess(c): global RunNode,ExitCode,WorkDir global In,OutThread,ErrThread # Close file and get error code. In.close() OutThread.File.close() ExitCode = ErrThread.File.close() # Unmark the node and reset it. RunNode.clearMarked() RunNode = None # Reset the working dir. if WorkDir != None: os.chdir(WorkDir) WorkDir = None # Write exit code. if ExitCode is None: g.blue("@run done") else: g.error("@run exits with code: %s" % (str(ExitCode))) # Redraw. c.redraw()
def writeFileFromNode(self, event=None): '''If node starts with @read-file-into-node, use the full path name in the headline. Otherwise, prompt for a file name. ''' c = self; p = c.p c.endEditing() h = p.h.rstrip() s = p.b tag = '@read-file-into-node' if h.startswith(tag): fileName = h[len(tag):].strip() else: fileName = None if not fileName: filetypes = [("All files", "*"), ("Python files", "*.py"), ("Leo files", "*.leo"),] fileName = g.app.gui.runSaveFileDialog(c, initialfile=None, title='Write File From Node', filetypes=filetypes, defaultextension=None) if fileName: try: with open(fileName, 'w') as f: g.chdir(fileName) if s.startswith('@nocolor\n'): s = s[len('@nocolor\n'):] if not g.isPython3: # 2010/08/27 s = g.toEncodedString(s, reportErrors=True) f.write(s) f.flush() g.blue('wrote:', fileName) except IOError: g.error('can not write %s', fileName)
def scan(self, s, parent): '''Create an outline from a MindMap (.csv) file.''' # pylint: disable=no-member # pylint confuses this module with the stdlib json module c = self.c self.gnx_dict = {} try: d = json.loads(s) for d2 in d.get('nodes', []): gnx = d2.get('gnx') self.gnx_dict[gnx] = d2 top_d = d.get('top') if top_d: # Don't set parent.h or parent.gnx or parent.v.u. parent.b = top_d.get('b') or '' self.create_nodes(parent, top_d) c.redraw() return bool(top_d) except Exception: # Fix #1098 try: obj = json.loads(s) except Exception: g.error('Bad .json file: %s' % parent.h) g.es_exception() obj = s parent.b = g.objToString(obj) c.redraw() return True
def create_temp_file(self, c, ext, p): ''' Create the temp file used by open-with if necessary. Add the corresponding ExternalFile instance to self.files ''' trace = False and not g.unitTesting if trace: g.trace(len(p.b), p.h) path = self.temp_file_path(c, p, ext) exists = g.os_path_exists(path) if trace: kind = 'recreating:' if exists else 'creating: ' g.trace(kind, path) # Compute encoding and s. d2 = c.scanAllDirectives(p) encoding = d2.get('encoding', None) if encoding is None: encoding = c.config.default_derived_file_encoding s = g.toEncodedString(p.b, encoding, reportErrors=True) # Write the file *only* if it doesn't exist. # No need to read the file: recomputing s above suffices. if not exists: try: f = open(path, 'wb') f.write(s) f.flush() f.close() except IOError: g.error('exception creating temp file: %s' % path) g.es_exception() return None # Add or update the external file entry. time = self.get_mtime(path) self.files = [z for z in self.files if z.path != path] self.files.append(ExternalFile(c, ext, p, path, time)) return path
def compute_temp_file_path(self, c, p, ext): '''Return the path to the temp file for p and ext.''' if c.config.getBool('open-with-clean-filenames'): path = self.clean_file_name(c, ext, p) else: path = self.legacy_file_name(c, ext, p) if not path: g.error('c.temp_file_path failed') return path
def doMinidomTest( c ): '''This def performs a simple test on a node. Can the data be successfully parsed by minidom or not. Results are output to the log''' s = getString( c ) try: mdom = minidom.parseString( s ) except Exception as x: g.error("Minidom could not parse node because of:\n %s" % x) return g.blue("Minidom could parse the node")
def runDebugScriptCommand (self,event=None): '''Called when user presses the 'debug-script' button or executes the debug-script command.''' c = self.c ; p = c.p script = g.getScript(c,p,useSelectedText=True,useSentinels=False) if script: #@+<< set debugging if debugger is active >> #@+node:ekr.20060523084441: *5* << set debugging if debugger is active >> g.trace(self.debuggerKind) if self.debuggerKind == 'winpdb': try: import rpdb2 debugging = rpdb2.g_debugger is not None except ImportError: debugging = False elif self.debuggerKind == 'idle': # import idlelib.Debugger.py as Debugger # debugging = Debugger.interacting debugging = True else: debugging = False #@-<< set debugging if debugger is active >> if debugging: #@+<< create leoScriptModule >> #@+node:ekr.20060524073716: *5* << create leoScriptModule >> (mod_scripting.py) target = g.os_path_join(g.app.loadDir,'leoScriptModule.py') f = None try: f = file(target,'w') f.write('# A module holding the script to be debugged.\n') if self.debuggerKind == 'idle': # This works, but uses the lame pdb debugger. f.write('import pdb\n') f.write('pdb.set_trace() # Hard breakpoint.\n') elif self.debuggerKind == 'winpdb': f.write('import rpdb2\n') f.write('if rpdb2.g_debugger is not None: # don\'t hang if the debugger isn\'t running.\n') f.write(' rpdb2.start_embedded_debugger(pwd="",fAllowUnencrypted=True) # Hard breakpoint.\n') # f.write('# Remove all previous variables.\n') f.write('# Predefine c, g and p.\n') f.write('import leo.core.leoGlobals as g\n') f.write('c = g.app.scriptDict.get("c")\n') f.write('p = c.p\n') f.write('# Actual script starts here.\n') f.write(script + '\n') finally: if f: f.close() #@-<< create leoScriptModule >> # pylint: disable=no-name-in-module g.app.scriptDict ['c'] = c if 'leoScriptModule' in sys.modules.keys(): del sys.modules ['leoScriptModule'] # Essential. import leo.core.leoScriptModule as leoScriptModule else: g.error('No debugger active') c.bodyWantsFocus()
def getLeoID(self): import os import sys g = self.g; tag = ".leoID.txt" homeDir = g.app.homeLeoDir globalConfigDir = g.app.globalConfigDir loadDir = g.app.loadDir verbose = False and not g.app.unitTesting #@+<< try to get leoID from sys.leoID >> #@+node:ekr.20070227094232.1: *5* << try to get leoID from sys.leoID>> # This would be set by in Python's sitecustomize.py file. # Use hasattr & getattr to suppress pylint warning. # We also have to use a "non-constant" attribute to suppress another warning! nonConstantAttr = "leoID" if hasattr(sys, nonConstantAttr): g.app.leoID = getattr(sys, nonConstantAttr) if verbose and not g.app.silentMode: g.red("leoID=", g.app.leoID, spaces=False) #@-<< try to get leoID from sys.leoID >> if not g.app.leoID: #@+<< try to get leoID from "leoID.txt" >> #@+node:ekr.20070227094232.2: *5* << try to get leoID from "leoID.txt" >> for theDir in (homeDir, globalConfigDir, loadDir): # N.B. We would use the _working_ directory if theDir is None! if theDir: try: fn = g.os_path_join(theDir, tag) f = open(fn, 'r') s = f.readline() f.close() if s and len(s) > 0: g.app.leoID = s.strip() if verbose and not g.app.silentMode: g.red('leoID=', g.app.leoID, ' (in ', theDir, ')', spaces=False) break elif verbose: g.red('empty ', tag, ' (in ', theDir, ')', spaces=False) except IOError: g.app.leoID = None except Exception: g.app.leoID = None g.error('unexpected exception in app.setLeoID') g.es_exception() #@-<< try to get leoID from "leoID.txt" >> if not g.app.leoID: #@+<< try to get leoID from os.getenv('USER') >> #@+node:ekr.20070227094232.3: *5* << try to get leoID from os.getenv('USER') >> try: theId = os.getenv('USER') if theId: if verbose: g.red("using os.getenv('USER'):", repr(theId)) g.app.leoID = theId except Exception: pass #@-<< try to get leoID from os.getenv('USER') >> return g.app.leoID
def OnQuit(tag,keywords=None): global RunNode,RunList if RunList: RunList = None g.disableIdleTimeHook() if RunNode: CloseProcess() g.error("@run: forced quit!")
def loadLinksInt(self): """load links after file opened or reload on request from UI""" c = self.c # checked in loadLinks() self.initIvars() # clears self.vnode idsSeen = set() # just the vnodes with link info. # make map from linked node's ids to their vnodes for p in c.all_positions(): v = p.v self.vnode[v.gnx] = v if v.u and '_bklnk' in v.u: idsSeen.add(v.gnx) for vnode in idsSeen: # just the vnodes with link info. if 'links' not in self.vnode[vnode].u['_bklnk']: g.trace(self.vnode[vnode].u) # graphcanvas.py will only init x and y keys self.vnode[vnode].u['_bklnk']['links'] = [] links = self.vnode[vnode].u['_bklnk']['links'] newlinks = [] # start with empty list and include only good links for link in links: if link[1] not in self.vnode: # other end if missing lt = ('to', 'from') if link[0] == 'S': lt = ('from', 'to') # use g.es rather than showMessage here g.error('backlink: link %s %s %s ??? lost' % ( lt[0], self.vnode[vnode].h, lt[1])) continue # check other end has link other = self.vnode[link[1]] if '_bklnk' not in other.u or 'links' not in other.u['_bklnk']: self.initBacklink(other) if not [ i for i in other.u['_bklnk']['links'] if i[1] == vnode ]: # we are not in the other's list direc = {'U':'U', 'S':'D', 'D':'S'}[link[0]] other.u['_bklnk']['links'].append((direc, vnode)) newlinks.append((link[0], link[1])) self.vnode[vnode].u['_bklnk']['links'] = newlinks self.showMessage('Link info. loaded on %d nodes' % len(idsSeen))
def createIconButton (self,text,command,statusLine,bg=None,kind=None): '''Create an icon button. All icon buttons get created using this utility. - Creates the actual button and its balloon. - Adds the button to buttonsDict. - Registers command with the shortcut. - Creates x amd delete-x-button commands, where x is the cleaned button name. - Binds a right-click in the button to a callback that deletes the button.''' c = self.c ; k = c.k # Create the button and add it to the buttons dict. commandName = self.cleanButtonText(text) # Truncate only the text of the button, not the command name. truncatedText = self.truncateButtonText(commandName) if not truncatedText.strip(): g.error('%s ignored: no cleaned text' % (text.strip() or '')) return None # Command may be None. b = self.iconBar.add(text=truncatedText,command=command,kind=kind) if not b: return None if bg: if not bg.startswith('#'): d = leoColor.leo_color_database bg2 = d.get(bg.lower()) if not bg2: print('bad color? %s' % bg) bg = bg2 if bg: try: b.button.setStyleSheet("QPushButton{background-color: %s}" % (bg)) except Exception: # g.es_exception() pass # Might not be a valid color. self.buttonsDict[b] = truncatedText if statusLine: self.createBalloon(b,statusLine) # Register the command name if it exists. if command: self.registerTwoCommands(text,func=command, pane='button',tag='icon button') # Define the callback used to delete the button. def deleteButtonCallback(event=None,self=self,b=b): self.deleteButton(b, event=event) # Register the delete-x-button command. deleteCommandName= 'delete-%s-button' % commandName k.registerCommand(deleteCommandName,shortcut=None, func=deleteButtonCallback,pane='button',verbose=False) # Reporting this command is way too annoying. return b
def createIconButton(self, args, text, command, statusLine, bg=None, kind=None): ''' Create one icon button. This method creates all scripting icon buttons. - Creates the actual button and its balloon. - Adds the button to buttonsDict. - Registers command with the shortcut. - Creates x amd delete-x-button commands, where x is the cleaned button name. - Binds a right-click in the button to a callback that deletes the button. ''' c = self.c # Create the button and add it to the buttons dict. commandName = self.cleanButtonText(text) # Truncate only the text of the button, not the command name. truncatedText = self.truncateButtonText(commandName) if not truncatedText.strip(): g.error('%s ignored: no cleaned text' % (text.strip() or '')) return None # Command may be None. b = self.iconBar.add(text=truncatedText, command=command, kind=kind) if not b: return None self.setButtonColor(b, bg) self.buttonsDict[b] = truncatedText if statusLine: self.createBalloon(b, statusLine) if command: self.registerAllCommands( args=args, func=command, h=text, pane='button', source_c=c, tag='icon button') def deleteButtonCallback(event=None, self=self, b=b): self.deleteButton(b, event=event) # Register the delete-x-button command. deleteCommandName = 'delete-%s-button' % commandName c.k.registerCommand( # allowBinding=True, commandName=deleteCommandName, func=deleteButtonCallback, pane='button', shortcut=None, ) # Reporting this command is way too annoying. return b
def get_script_node_info(self, s, delim2): '''Return the gnx and headline of a #@+node.''' i = s.find(':', 0) j = s.find(':', i + 1) if i == -1 or j == -1: g.error("bad @+node sentinel", s) return None, None else: gnx = s[i + 1: j] h = s[j + 1:] h = self.remove_level_stars(h).strip() if delim2: h = h.rstrip(delim2) return gnx, h
def create(self, fn): '''Create the given file with empty contents.''' theDir = g.os_path_dirname(fn) g.makeAllNonExistentDirectories(theDir, c=self.c, force=True, verbose=True) # Make the directories as needed. try: f = open(fn, mode='wb') f.close() g.note('created: %s' % (fn)) except IOError: g.error('can not create: %s' % (fn)) except Exception: g.error('unexpected error creating: %s' % (fn)) g.es_exception()
def createOpenWithMenuFromTable(self, table): ''' Table is a list of dictionaries, created from @openwith settings nodes. This menu code uses these keys: 'name': menu label. 'shortcut': optional menu shortcut. efc.open_temp_file uses these keys: 'args': the command-line arguments to be used to open the file. 'ext': the file extension. 'kind': the method used to open the file, such as subprocess.Popen. ''' # trace = False and not g.unitTesting k = self.c.k if not table: return g.app.openWithTable = table # Override any previous table. # Delete the previous entry. parent = self.getMenu("File") # if trace: g.trace('parent',parent) if not parent: if not g.app.batchMode: g.error('', 'createOpenWithMenuFromTable:', 'no File menu') return label = self.getRealMenuName("Open &With...") amp_index = label.find("&") label = label.replace("&", "") try: index = parent.index(label) parent.delete(index) except Exception: try: index = parent.index("Open With...") parent.delete(index) except Exception: g.trace('unexpected exception') g.es_exception() return # Create the Open With menu. openWithMenu = self.createOpenWithMenu(parent, label, index, amp_index) if not openWithMenu: g.trace('openWithMenu returns None') return self.setMenu("Open With...", openWithMenu) # Create the menu items in of the Open With menu. self.createOpenWithMenuItemsFromTable(openWithMenu, table) for d in table: k.bindOpenWith(d)
def createFile(c, parent, d): """Ask if we should create a new file""" directory = os.path.dirname(d) if not os.path.isdir(directory): g.error("Create parent directories first") return False d = os.path.basename(d) atType = c.config.getString("active_path_attype") or "auto" ok = g.app.gui.runAskYesNoDialog(c, "Create / load file?", "Create file @" + atType + " " + d + "?") if ok == "no": return False c.setHeadString(parent, "@" + atType + " " + d) c.bodyWantsFocus() return True
def pickle(self, p): '''Pickle val and return the hexlified result.''' try: ua = p.v.u s = pickle.dumps(ua, protocol=1) s2 = binascii.hexlify(s) s3 = g.ue(s2, 'utf-8') return s3 except pickle.PicklingError: g.warning("ignoring non-pickleable value", ua, "in", p.h) return '' except Exception: g.error("pd.pickle: unexpected exception in", p.h) g.es_exception() return ''
def createFile(c,parent,d): """Ask if we should create a new file""" directory = os.path.dirname(d) if not os.path.isdir(directory): g.error('Create parent directories first') return False d = os.path.basename(d) atType = c.config.getString('active_path_attype') or 'auto' ok = g.app.gui.runAskYesNoDialog(c, 'Create / load file?', 'Create file @'+atType+' '+d+'?') if ok == 'no': return False c.setHeadString(parent, '@'+atType+' '+d) c.bodyWantsFocus() return True
def create_temp_file(self, c, d, p): ''' Create the temp file used by open-with if necessary. Add the corresponding ExternalFile instance to self.files d is a dictionary created from an @openwith settings node. 'args': the command-line arguments to be used to open the file. 'ext': the file extension. 'kind': the method used to open the file, such as subprocess.Popen. 'name': menu label (used only by the menu code). 'shortcut': menu shortcut (used only by the menu code). ''' trace = False and not g.unitTesting assert isinstance(d, dict), d ext = d.get('ext') path = self.temp_file_path(c, p, ext) exists = g.os_path_exists(path) if trace: kind = 'recreating:' if exists else 'creating: ' g.trace(kind, path) # Compute encoding and s. d2 = c.scanAllDirectives(p) encoding = d2.get('encoding', None) if encoding is None: encoding = c.config.default_derived_file_encoding s = g.toEncodedString(p.b, encoding, reportErrors=True) # Write the file *only* if it doesn't exist. # No need to read the file: recomputing s above suffices. if not exists: try: f = open(path, 'wb') f.write(s) f.flush() f.close() except IOError: g.error('exception creating temp file: %s' % path) g.es_exception() return None # Add or update the external file entry. time = self.get_mtime(path) self.files = [z for z in self.files if z.path != path] self.files.append(ExternalFile(c, ext, p, path, time)) return path
def pickle (self,p): '''Pickle val and return the hexlified result.''' trace = False and g.unitTesting try: ua = p.v.u s = pickle.dumps(ua,protocol=1) s2 = binascii.hexlify(s) s3 = g.ue(s2,'utf-8') if trace: g.trace('\n', type(ua),ua,'\n',type(s),repr(s),'\n', type(s2),s2,'\n',type(s3),s3) return s3 except pickle.PicklingError: g.warning("ignoring non-pickleable value",ua,"in",p.h) return '' except Exception: g.error("pd.pickle: unexpected exception in",p.h) g.es_exception() return ''
def pickle(self, p): '''Pickle val and return the hexlified result.''' trace = False and g.unitTesting try: ua = p.v.u s = pickle.dumps(ua, protocol=1) s2 = binascii.hexlify(s) s3 = g.ue(s2, 'utf-8') if trace: g.trace('\n', type(ua), ua, '\n', type(s), repr(s), '\n', type(s2), s2, '\n', type(s3), s3) return s3 except pickle.PicklingError: g.warning("ignoring non-pickleable value", ua, "in", p.h) return '' except Exception: g.error("pd.pickle: unexpected exception in", p.h) g.es_exception() return ''
def write(self, name, data, basedir=None, path=None): """Write a single file. The `name` can be a file name or a ralative path which will be added to basedir and path to create a full path for the file to be written. If basedir is None self.basedir will be used and if path is none self.path will be used. """ if basedir is None: basedir = self.basedir if path is None: path = self.path filepath = abspath(basedir,path,name) # g.trace('basedir',basedir,'path',path,'name',name) try: f = open(filepath, 'wb') except Exception: g.error('can not open: %s' % (filepath)) g.es_exception(full=False,c=self.c) return False try: try: f.write(data.encode('utf-8')) self.announce('output file: %s' % (filepath), color=self.fileColor) ok = True except Exception: g.error('write failed: %s' % (filepath)) g.es_exception(full=False,c=self.c) ok = False finally: f.close() return ok
def cmd_Export(event): '''Export the current node to Word''' c = event.get('c') try: word = getWordConnection() if word: # header_style = getConfiguration().get("Main", "Header_Style") # Based on the rst plugin g.blue("Writing tree to Word") config = getConfiguration() writeNodeAndTree( c, word, config.get("Main", "header_style").strip(), 1, int(config.get("Main", "max_headings")), config.get("Main", "use_section_numbers") == "Yes", "") g.es("Done!") except Exception: g.error("Exception writing Word") g.es_exception()
def write(self, name, data, basedir=None, path=None): """Write a single file. The `name` can be a file name or a ralative path which will be added to basedir and path to create a full path for the file to be written. If basedir is None self.basedir will be used and if path is none self.path will be used. """ if basedir is None: basedir = self.basedir if path is None: path = self.path filepath = abspath(basedir, path, name) # g.trace('basedir',basedir,'path',path,'name',name) try: f = open(filepath, 'wb') except Exception: g.error('can not open: %s' % (filepath)) g.es_exception(full=False, c=self.c) return False try: try: f.write(data.encode('utf-8')) self.announce('output file: %s' % (filepath), color=self.fileColor) ok = True except Exception: g.error('write failed: %s' % (filepath)) g.es_exception(full=False, c=self.c) ok = False finally: f.close() return ok
def parse_opml_file(self, fn): c = self.c if not fn or not fn.endswith(".opml"): return g.trace("bad file name: %s" % repr(fn)) c = self.c path = g.os_path_normpath(g.os_path_join(g.app.loadDir, fn)) try: f = open(path, "rb") s = f.read() # type(s) is bytes for Python 3.x. s = self.cleanSaxInputString(s) except IOError: return g.trace("can not open %s" % path) try: if g.isPython3: theFile = BytesIO(s) else: theFile = cStringIO.StringIO(s) parser = xml.sax.make_parser() parser.setFeature(xml.sax.handler.feature_external_ges, 1) # Do not include external general entities. # The actual feature name is "http://xml.org/sax/features/external-general-entities" parser.setFeature(xml.sax.handler.feature_external_pes, 0) handler = SaxContentHandler(c, fn) parser.setContentHandler(handler) parser.parse(theFile) # expat does not support parseString sax_node = handler.getNode() except xml.sax.SAXParseException: g.error("error parsing", fn) g.es_exception() sax_node = None except Exception: g.error("unexpected exception parsing", fn) g.es_exception() sax_node = None return sax_node
def parse_opml_file(self, fn): c = self.c if not fn or not fn.endswith('.opml'): return g.trace('bad file name: %s' % repr(fn)) c = self.c path = g.os_path_normpath(g.os_path_join(g.app.loadDir, fn)) try: f = open(path, 'rb') s = f.read() # type(s) is bytes for Python 3.x. s = self.cleanSaxInputString(s) except IOError: return g.trace('can not open %s' % path) try: if g.isPython3: theFile = BytesIO(s) else: theFile = cStringIO.StringIO(s) parser = xml.sax.make_parser() parser.setFeature(xml.sax.handler.feature_external_ges, 1) # Do not include external general entities. # The actual feature name is "http://xml.org/sax/features/external-general-entities" parser.setFeature(xml.sax.handler.feature_external_pes, 0) handler = SaxContentHandler(c, fn) parser.setContentHandler(handler) parser.parse(theFile) # expat does not support parseString sax_node = handler.getNode() except xml.sax.SAXParseException: g.error('error parsing', fn) g.es_exception() sax_node = None except Exception: g.error('unexpected exception parsing', fn) g.es_exception() sax_node = None return sax_node
def stop (tag,keywords): c = keywords.get('c') if not c: g.trace('can not happen') return multi = scanForMultiPath(c) for fileName in multi: paths = multi.get(fileName) for path in paths: try: if os.path.isdir(path): shutil.copy2(fileName,path) g.blue("multifile:\nWrote %s to %s" % (fileName,path)) else: g.error("multifile:\n%s is not a directory, not writing %s" % (path,fileName)) except Exception: g.error("multifile:\nCant write %s to %s" % (fileName,path)) g.es_exception_type() files.clear()
def createDirectoryForFile(self, fn): """ Create the directory for fn if a) it doesn't exist and b) the user options allow it. Return True if the directory existed or was made. """ c, ok = self.c, False # 1815. # Create the directory if it doesn't exist. theDir, junk = g.os_path_split(fn) theDir = g.os_path_finalize(theDir) # 1341 if g.os_path_exists(theDir): return True if c and c.config and c.config.create_nonexistent_directories: theDir = c.expand_path_expression(theDir) ok = g.makeAllNonExistentDirectories(theDir) if not ok: g.error('did not create:', theDir) return ok
def OnBodyKey(tag,keywords): global RunNode,In c=keywords.get('c') if not c or not c.exists: return p=c.p h=p.h ch=keywords.get("ch") # handle the @run "\r" body key if ch == "\r" and g.match_word(h,0,"@run") and RunNode and RunNode==p: try: In.write(p.b.encode(Encoding)) In.flush() g.es(p.b) except IOError as ioerr: g.error("[@run] IOError: "+str(ioerr)) return c.setBodyText(p,"")
def OnIconDoubleClick(tag, keywords): global RunNode, RunList, OwnIdleHook, ExitCode c = keywords.get('c') if not c or not c.exists: return p = c.p # g.trace(c.shortFileName()) h = p.h if g.match_word(h, 0, "@run"): if RunNode or RunList: g.error("@run already running!") else: #@+<< handle double click in @run icon >> #@+node:ekr.20040910102554: *4* << handle double click in @run icon >> RunList = [] for p2 in p.self_and_subtree(): if g.match_word(p2.h, 0, "@run"): # g.trace(p2.h) # 2009/10/30: don't use iter copy arg. RunList.append(p2.copy()) ExitCode = None OwnIdleHook = True ### g.enableIdleTimeHook() #@-<< handle double click in @run icon >> elif g.match_word(h, 0, "@in"): if RunNode: #@+<< handle double click in @in icon >> #@+node:ekr.20040910102554.1: *4* << handle double click in @in icon >> b = p.b try: In.write(b.encode(Encoding) + "\n") In.flush() g.es(b) except IOError as ioerr: g.error("@run IOError: " + str(ioerr))
def createAttrib(self, event=None, readonly=False): ans = [] for getter, isOn in self.getsetters: if not isOn: continue if getter.helpCreate() is True: ans.append(getter) else: g.es("For '%s' attributes:\n %s" % (getter.name(), getter.helpCreate())) if len(ans) > 1: g.error('Eror: more than one attribute type (%s) active' % ', '.join([i.name() for i in ans])) elif ans: ans[0].createAttrib(self.c.currentPosition().v, gui_parent=self.parent) self.updateEditorInt() self.c.currentPosition().v.setDirty() self.c.redraw()
def reportChangedClone (self,child_v,b,h,gnx): trace = False and not g.unitTesting c = self.c fileName=c.cacheListFileName old,new = child_v.b,b same = ( old == new or new.endswith('\n') and old == new[:-1] or old.endswith('\n') and new == old[:-1]) # if trace and not same: if trace and (not same or h == 'writeException'): g.trace('same %s old %s new %s %s %s' % ( same,len(old),len(new),h,fileName)) # This would make it impossible to clear nodes! # if not new: return same if same: return c.nodeConflictList.append(g.bunch( tag='(cached)', fileName=fileName, gnx=gnx, b_old=child_v.b, h_old=child_v.h, b_new=b, h_new=h, )) # Always issue the warning. g.error("cached read node changed:",child_v.h) child_v.h,child_v.b = h,b child_v.setDirty() c.changed = True # Tell getLeoFile to propegate dirty nodes.
def OLD_parse_opml_file(self, inputFileName): if not inputFileName or not inputFileName.endswith('.opml'): return None c = self.c path = g.os_path_normpath( g.os_path_join(g.app.loadDir, inputFileName)) try: f = open(path) except IOError: g.trace('can not open %s' % path) return None try: # pylint:disable=catching-non-exception try: node = None parser = xml.sax.make_parser() # Do not include external general entities. # The actual feature name is "http://xml.org/sax/features/external-general-entities" parser.setFeature(xml.sax.handler.feature_external_ges, 0) handler = SaxContentHandler(c, inputFileName) parser.setContentHandler(handler) parser.parse(f) node = handler.getNode() except xml.sax.SAXParseException: g.error('Error parsing %s' % (inputFileName)) g.es_exception() node = None except Exception: g.error('Unexpected exception parsing %s' % (inputFileName)) g.es_exception() node = None finally: f.close() return node
def writeFileFromNode(self, event=None): '''If node starts with @read-file-into-node, use the full path name in the headline. Otherwise, prompt for a file name. ''' c = self p = c.p c.endEditing() h = p.h.rstrip() s = p.b tag = '@read-file-into-node' if h.startswith(tag): fileName = h[len(tag):].strip() else: fileName = None if not fileName: filetypes = [ ("All files", "*"), ("Python files", "*.py"), ("Leo files", "*.leo"), ] fileName = g.app.gui.runSaveFileDialog(c, initialfile=None, title='Write File From Node', filetypes=filetypes, defaultextension=None) if fileName: try: with open(fileName, 'w') as f: g.chdir(fileName) if s.startswith('@nocolor\n'): s = s[len('@nocolor\n'):] if not g.isPython3: # 2010/08/27 s = g.toEncodedString(s, reportErrors=True) f.write(s) f.flush() g.blue('wrote:', fileName) except IOError: g.error('can not write %s', fileName)
def open_with_helper(self, c, ext, p): ''' Reopen a temp file for p if it exists in self.files. Otherwise, open a new temp file. ''' path = self.temp_file_path(c, p, ext) if not path: return g.error('c.temp_file_path failed') # # Return a path if a temp file already refers to p.v for ef in self.files: if path and path == ef.path and p.v == ef.p.v: return ef.path # # Not found: create the temp file. return self.create_temp_file(c, ext, p)
def open_with_helper(self, c, ext, p): ''' Reopen a temp file for p if it exists in self.files. Otherwise, open a new temp file. ''' trace = False and not g.unitTesting path = self.temp_file_path(c, p, ext) if not path: return g.error('c.temp_file_path failed') # Return a path if a temp file already refers to p.v for ef in self.files: if path and path == ef.path and p.v == ef.p.v: if trace: g.trace('found!', path) return ef.path # Not found: create the temp file. if trace: g.trace('not found', path) return self.create_temp_file(c, ext, p)
def open_with_helper(self, c, d, p): ''' Reopen a temp file for p if it exists in self.files. Otherwise, open a new temp file. ''' trace = False and not g.unitTesting assert isinstance(d, dict), d # May be over-ridden by mod_tempfname plugin. path = self.temp_file_path(c, p, d.get('ext')) if not path: # Check the mod_tempfname plugin. return g.error('c.temp_file_path failed') # Return a path if a temp file already refers to p.v for ef in self.files: if path and path == ef.path and p.v == ef.p.v: if trace: g.trace('found!', path) return ef.path # Not found: create the temp file. if trace: g.trace('not found', path) return self.create_temp_file(c, d, p)
def create(self, fn): """Create the given file with empty contents.""" # Make the directories as needed. theDir = g.os_path_dirname(fn) if theDir: ok = g.makeAllNonExistentDirectories(theDir) # #1453: Don't assume the directory exists. if not ok: g.error(f"did not create directory: {theDir}") return # Create the file. try: f = open(fn, mode='wb') f.close() g.note(f"created: {fn}") except IOError: g.error(f"can not create: {fn}") except Exception: g.error(f"unexpected error creating: {fn}") g.es_exception()
def run_sphinx(self, i_path, o_path): """Process i_path and o_path with sphinx.""" trace = True # cd to the command directory, or i_path's directory. command_dir = g.os_path_finalize(self.sphinx_command_dir or os.path.dirname(i_path)) if os.path.exists(command_dir): if trace: g.trace(f"\nos.chdir: {command_dir!r}") os.chdir(command_dir) else: g.error(f"command directory not found: {command_dir!r}") return # # If a default command exists, just call it. # The user is responsible for making everything work. if self.sphinx_default_command: if trace: g.trace(f"\ncommand: {self.sphinx_default_command!r}\n") g.execute_shell_commands(self.sphinx_default_command) return # Compute the input directory. input_dir = g.os_path_finalize(self.sphinx_input_dir or os.path.dirname(i_path)) if not os.path.exists(input_dir): g.error(f"input directory not found: {input_dir!r}") return # Compute the output directory. output_dir = g.os_path_finalize(self.sphinx_output_dir or os.path.dirname(o_path)) if not os.path.exists(output_dir): g.error(f"output directory not found: {output_dir!r}") return # # Call sphinx-build to write the output file. # sphinx-build [OPTIONS] SOURCEDIR OUTPUTDIR [FILENAMES...] command = f"sphinx-build {input_dir} {output_dir} {i_path}" if trace: g.trace(f"\ncommand: {command!r}\n") g.execute_shell_commands(command)
def runDebugScriptCommand(self, event=None): '''Called when user presses the 'debug-script' button or executes the debug-script command.''' c = self.c p = c.p script = g.getScript(c, p, useSelectedText=True, useSentinels=False) if script: #@+<< set debugging if debugger is active >> #@+node:ekr.20060523084441: *6* << set debugging if debugger is active >> g.trace(self.debuggerKind) if self.debuggerKind == 'winpdb': try: import rpdb2 debugging = rpdb2.g_debugger is not None except ImportError: debugging = False elif self.debuggerKind == 'idle': # import idlelib.Debugger.py as Debugger # debugging = Debugger.interacting debugging = True else: debugging = False #@-<< set debugging if debugger is active >> if debugging: #@+<< create leoScriptModule >> #@+node:ekr.20060524073716: *6* << create leoScriptModule >> target = g.os_path_join(g.app.loadDir, 'leoScriptModule.py') f = None try: f = file(target, 'w') f.write('# A module holding the script to be debugged.\n') if self.debuggerKind == 'idle': # This works, but uses the lame pdb debugger. f.write('import pdb\n') f.write('pdb.set_trace() # Hard breakpoint.\n') elif self.debuggerKind == 'winpdb': f.write('import rpdb2\n') f.write( 'if rpdb2.g_debugger is not None: # don\'t hang if the debugger isn\'t running.\n' ) f.write( ' rpdb2.start_embedded_debugger(pwd="",fAllowUnencrypted=True) # Hard breakpoint.\n' ) # f.write('# Remove all previous variables.\n') f.write('# Predefine c, g and p.\n') f.write('import leo.core.leoGlobals as g\n') f.write('c = g.app.scriptDict.get("c")\n') f.write('p = c.p\n') f.write('# Actual script starts here.\n') f.write(script + '\n') finally: if f: f.close() #@-<< create leoScriptModule >> # pylint: disable=E0611 # E0611:runDebugScriptCommand: No name 'leoScriptModule' in module 'leo.core' g.app.scriptDict['c'] = c if 'leoScriptModule' in sys.modules.keys(): del sys.modules['leoScriptModule'] # Essential. import leo.core.leoScriptModule as leoScriptModule else: g.error('No debugger active') c.frame.bodyWantsFocus()
def error(self, s): g.error('Error: %s' % (s))
def OpenProcess(p): global RunNode,WorkDir global In,OutThread,ErrThread,ExitCode command = p.h[4:].strip() # Remove @run if not command: return #@+<< set the working directory or return >> #@+node:ekr.20040910094754: *3* << set the working directory or return >> args = command.split(' ') path,fname = os.path.split(args[0]) if g.match(fname,0,'#'): return if path: if os.access(path,os.F_OK) == 1: WorkDir=os.getcwd() os.chdir(path) else: g.error("@run: invalid path: %s" % (path)) return #@-<< set the working directory or return >> #@+<< set the command, removing all args following '#' >> #@+node:ekr.20040910100935: *3* << set the command, removing all args following '#' >> command = fname for arg in args[1:]: if g.match(arg,0,'#'): break else: command += ' ' + arg.strip() #@-<< set the command, removing all args following '#' >> if not command.strip(): return RunNode=p args = [] #@+<< append arguments from child nodes to command >> #@+node:ekr.20040910095147: *3* << append arguments from child nodes to command >> for child in p.children(): h = child.h if g.match_word(h,0,"@arg"): arg = h[4:].strip() args.append(arg) else: if ( not g.match_word(h,0,"@run") and not g.match_word(h,0,"@in") and not g.match_word(h,0,"@input") ): args.append(child.b.strip()) #@-<< append arguments from child nodes to command >> g.blue("@run %s>%s" % (os.getcwd(),command)) for arg in args: g.blue("@arg %s" % arg) command += ' ' + ' '.join(args) # Start the threads and open the pipe. OutThread = readingThread() ErrThread = readingThread() # In,OutThread.File,ErrThread.File = os.popen3(command,"t") # OutThread.File,In,ErrThread.File = os.popen3(command,"t") # PIPE = subprocess.PIPE proc = subprocess.Popen(command, shell=True) # bufsize=bufsize, # stdin=PIPE, # stdout=PIPE, # stderr=PIPE) ,close_fds=True) In = proc.stdin OutThread.File = proc.stdout ErrThread.File = proc.stderr OutThread.start() ErrThread.start() # Mark and select the node. RunNode.setMarked() c = RunNode.v.context c.selectPosition(RunNode) if os.name in ("nt","dos"): c.redraw()
def dtest(self, event): """The handler for dtest """ import leo.core.leoGlobals as g # get a valid temporary filename createfile, tempfilename = g.create_temp_file() createfile.close() selected = False # if text is selected, only test selection if self.c.frame.body.hasTextSelection(): selected = True selection = self.c.frame.body.getSelectedText() tempfile = open(tempfilename, 'w') tempfile.write(selection) tempfile.close() # if no selection, test this subtree else: self.c.importCommands.flattenOutline(tempfilename) tempfile = open(tempfilename) text = tempfile.readlines() tempfile.close() # strip trailing whitespace, an annoying source of doctest failures text = [line.rstrip() for line in text] text = "\n".join(text) tempfile = open(tempfilename, 'w') tempfile.write(text) tempfile.close() import copy # build globals dictionary globals = {'c': copy.copy(self.c), 'g': g} # run doctest on temporary file failures, tests = doctest.testfile(tempfilename, module_relative=False, optionflags=doctest.ELLIPSIS, globs=globals) #@+<<report summary of results>> #@+node:ekr.20070119094733.10: *4* <<report summary of results>> if selected: g.es('Result of running doctest on selected text;') else: g.es('Result of running doctest on this subtree;') if failures == 0: g.blue("%s tests run successfully" % tests) if failures == 1: g.error("There was one failure in %s tests" % tests) if failures > 1: g.error("%s failures in %s tests" % (failures, tests)) #@-<<report summary of results>> #clean up temp file os.remove(tempfilename)
def moveCurrentNodeToTarget(self, checked=False): '''Move the current position to the last child of self.target.''' c = self.c p = c.p vnodes = [i.v for i in c.getSelectedPositions()] needs_undo = self.type_ != "jump" if needs_undo: bunch = c.undoer.beforeMoveNode(p) for v in vnodes: p2 = c.vnode2position(self.target) p = c.vnode2position(v) if not c.positionExists(p2): g.error('Target no longer exists: %s' % self.targetHeadString) return if self.type_ in ('clone', 'move'): # all others are always valid? if p.v == p2.v or not self.checkMove(p, p2): g.error('Invalid move: %s' % (self.targetHeadString)) return if p2.isAncestorOf(p): # not for sibling moves p2.expand() nxt = p.visNext(c) or p.visBack(c) nxt = nxt.v # store a VNode instead of position as positions are too easily lost if self.type_ != 'jump': p.setDirty() # before move to dirty current parent p2.setDirty() c.setChanged() if self.type_ == 'clone': p = p.clone() if self.type_ in ('move', 'clone'): if self.which == 'first child': p.moveToFirstChildOf(p2) elif self.which == 'last child': p.moveToLastChildOf(p2) elif self.which in ('next sibling', 'prev sibling'): if not p2.parent(): raise Exception( "Not implemented for top-level nodes") #FIXME if self.which == 'next sibling': p.moveToNthChildOf(p2.parent(), p2._childIndex) elif self.which == 'prev sibling': p.moveToNthChildOf(p2.parent(), p2._childIndex - 1) else: raise Exception("Unknown move type " + self.which) elif self.type_ == 'bkmk': unl = self.computeUNL(p) # before tree changes if self.which == 'first child': nd = p2.insertAsNthChild(0) elif self.which == 'last child': nd = p2.insertAsLastChild() elif self.which == 'next sibling': nd = p2.insertAfter() elif self.which == 'prev sibling': nd = p2.insertBefore() else: raise Exception("Unknown move type " + self.which) h = p.anyAtFileNodeName() or p.h while h and h[0] == '@': h = h[1:] nd.h = h nd.b = unl elif self.type_ == 'copy': if self.which == 'first child': nd = p2.insertAsNthChild(0) quickMove.copy_recursively(p, nd) # unlike p.copyTreeFromSelfTo, deepcopys p.v.u elif self.which == 'last child': nd = p2.insertAsLastChild() quickMove.copy_recursively(p, nd) elif self.which == 'next sibling': nd = p2.insertAfter() quickMove.copy_recursively(p, nd) elif self.which == 'prev sibling': nd = p2.insertBefore() quickMove.copy_recursively(p, nd) else: raise Exception("Unknown move type " + self.which) elif self.type_ in ('linkTo', 'linkFrom'): blc = getattr(c, 'backlinkController', None) if blc is None: g.es("Linking requires backlink.py plugin") return if self.type_ == 'linkTo': blc.vlink(p.v, p2.v) else: blc.vlink(p2.v, p.v) if self.type_ in ('bkmk', 'clone', 'copy', 'move'): nxt = c.vnode2position(nxt) elif self.type_ == 'jump': nxt = c.vnode2position(self.target) else: nxt = None # linkTo / linkFrom don't move if nxt is not None and c.positionExists(nxt): c.selectPosition(nxt) if needs_undo: c.undoer.afterMoveNode(p, 'Quick Move', bunch) c.setChanged() c.redraw()
def error(self, s): g.error(f"Error: {s}")
def editnode_on_idle(tag, keywords): #g.trace(tag,keywords) import os a = g.app if a.killed: return # g.trace('open with plugin') for dict in a.openWithFiles: path = dict.get("path") c = dict.get("c") encoding = dict.get("encoding", None) p = dict.get("p") old_body = dict.get("body") if path and os.path.exists(path): try: time = os.path.getmtime(path) # g.trace(path,time,dict.get('time')) if time and time != dict.get("time"): dict["time"] = time # inhibit endless dialog loop. # The file has changed. #@+<< set s to the file text >> #@+node:ville.20090701142447.5474: *3* << set s to the file text >> try: # Update v from the changed temp file. f = open(path) s = f.read() f.close() except: g.es("can not open " + g.shortFileName(path)) break #@-<< set s to the file text >> #@+<< update p's body text >> #@+node:ville.20090701142447.5475: *3* << update p's body text >> # Convert body and s to whatever encoding is in effect. body = p.b body = g.toEncodedString(body, encoding, reportErrors=True) s = g.toEncodedString(s, encoding, reportErrors=True) conflict = body != old_body and body != s # Set update if we should update the outline from the file. if conflict: # 2012/02/04: Don't raise dialog for files opened with vim.py, xemacs.py, etc. paths = [z.get('path') for z in g.app.openWithFiles] if path in paths: update = True else: # See how the user wants to resolve the conflict. g.error("conflict in " + g.shortFileName(path)) message = "Replace changed outline with external changes?" result = g.app.gui.runAskYesNoDialog( c, "Conflict!", message) update = result.lower() == "yes" else: update = s != body if update: g.blue("updated from: " + g.shortFileName(path)) s = g.toUnicode(s, encoding=encoding) c.setBodyString(p, s) #TL - 7/2/08 Converted to configurable 'goto node...' if c.config.getBool('open_with_goto_node_on_update'): c.selectPosition(p) dict["body"] = s # A patch by Terry Brown. if c.config.getBool('open_with_save_on_update'): c.save() elif conflict: g.blue("not updated from: " + g.shortFileName(path)) #@-<< update p's body text >> except Exception: # g.es_exception() pass
def open_mimetype(tag, keywords, val=None): """Simulate double-clicking on the filename in a file manager. Order of preference is: 1) @string mime_open_cmd setting 2) _mime_open_cmd, defined per sys.platform detection 3) open_func(fpath), defined per sys.platform detection 4) mailcap file for mimetype handling """ global open_func c = keywords.get('c') p = keywords.get('p') if not c or not p: return None if p.h.startswith('@mime'): fname = p.h[6:] # honor @path d = c.scanAllDirectives(p) path = d.get('path') fpath = g.os_path_finalize_join(path, fname) # stop here if the file doesn't exist if not g.os_path_exists(fpath): g.error('@mime: file does not exist, %s' % fpath) return True # user-specified command string, or sys.platform-determined string mime_cmd = c.config.getString('mime-open-cmd') or _mime_open_cmd if mime_cmd: if '%s' not in mime_cmd: mime_cmd += ' %s' open_func = exec_string_cmd(mime_cmd) #no special handler function specified (unknown platform), #try mailcap/mimetype entries explicitly if open_func is None: (ftype, encoding) = mimetypes.guess_type(fname) if ftype: caps = mailcap.getcaps() (fullcmd, entry) = mailcap.findmatch(caps, ftype, filename=fpath, key='view') if fullcmd: # create a function which merely executes the fullcmd in # a shell for e.g. PATH access open_func = exec_full_cmd(fullcmd) else: g.error('@mime: no mailcap entry for %s: %s' % (ftype, fname)) g.trace('mailcap command:', fullcmd) else: g.error('@mime: unknown file type: %s' % fname) # use the custom open_func to open external file viewer if open_func: open_func(fpath) else: g.error('@mime: no known way to open %s' % fname) # block execution of e.g. vim plugin return True # not an @mime node return val
def oops(message, i, j): # This can be called from c-to-python, in which case warnings should be suppressed. if giveWarnings: g.error('** changed ', p.h) g.es_print('%s after\n%s' % (message, repr(''.join(s[i:j]))))
def error(self, s): g.error('', s)
def moveCurrentNodeToTarget(self): '''Move the current position to the last child of self.target.''' c = self.c p = c.p p2 = c.vnode2position(self.target) needs_undo = self.type_ != "jump" if not c.positionExists(p2): g.error('Target no longer exists: %s' % self.targetHeadString) return if self.type_ in ('clone', 'move'): # all others are always valid? if p.v == p2.v or not self.checkMove(p, p2): g.error('Invalid move: %s' % (self.targetHeadString)) return if needs_undo: bunch = c.undoer.beforeMoveNode(p) p2.expand() nxt = p.visNext(c) or p.visBack(c) nxt = nxt.v # store a vnode instead of position as positions are too easily lost if self.type_ == 'clone': p = p.clone() if self.type_ in ('move', 'clone'): if self.first: p.moveToFirstChildOf(p2) else: p.moveToLastChildOf(p2) elif self.type_ == 'bkmk': unl = self.computeUNL(p) # before tree changes if self.first: nd = p2.insertAsNthChild(0) else: nd = p2.insertAsLastChild() h = p.anyAtFileNodeName() or p.h while h and h[0] == '@': h = h[1:] nd.h = h nd.b = unl elif self.type_ == 'copy': if self.first: nd = p2.insertAsNthChild(0) quickMove.copy_recursively(p, nd) # unlike p.copyTreeFromSelfTo, deepcopys p.v.u else: nd = p2.insertAsLastChild() quickMove.copy_recursively(p, nd) elif self.type_ in ('linkTo', 'linkFrom'): blc = getattr(c, 'backlinkController', None) if blc is None: g.es("Linking requires backlink.py plugin") return if self.type_ == 'linkTo': blc.vlink(p.v, p2.v) else: blc.vlink(p2.v, p.v) if self.type_ in ('bkmk', 'clone', 'copy', 'move'): nxt = c.vnode2position(nxt) elif self.type_ == 'jump': nxt = c.vnode2position(self.target) else: nxt = None # linkTo / linkFrom don't move if nxt is not None and c.positionExists(nxt): c.selectPosition(nxt) if needs_undo: c.undoer.afterMoveNode(p, 'Quick Move', bunch) c.setChanged(True) c.redraw()
def loadOnePlugin (self,moduleOrFileName,tag='open0',verbose=False): trace = False and not g.unitTesting verbose = False or verbose if not g.app.enablePlugins: if trace: g.trace('plugins disabled') return None if moduleOrFileName.startswith('@'): if trace: g.trace('ignoring Leo directive') return None # Return None, not False, to keep pylint happy. # Allow Leo directives in @enabled-plugins nodes. moduleName = self.regularizeName(moduleOrFileName) if self.isLoaded(moduleName): module = self.loadedModules.get(moduleName) if trace and verbose: g.warning('loadOnePlugin: plugin',moduleName,'already loaded') return module assert g.app.loadDir moduleName = g.toUnicode(moduleName) # This import will typically result in calls to registerHandler. # if the plugin does _not_ use the init top-level function. self.loadingModuleNameStack.append(moduleName) try: toplevel = __import__(moduleName) # need to look up through sys.modules, __import__ returns toplevel package result = sys.modules[moduleName] except g.UiTypeException: if not g.unitTesting and not g.app.batchMode: g.es_print('Plugin %s does not support %s gui' % ( moduleName,g.app.gui.guiName())) result = None except ImportError: if trace or tag == 'open0': # Just give the warning once. g.error('error importing plugin:',moduleName) g.es_exception() result = None except SyntaxError: if trace or tag == 'open0': # Just give the warning once. g.error('syntax error importing plugin:',moduleName) # g.es_exception() result = None except Exception as e: g.error('exception importing plugin ' + moduleName) g.es_exception() result = None self.loadingModuleNameStack.pop() if result: self.signonModule = result # for self.plugin_signon. self.loadingModuleNameStack.append(moduleName) if tag == 'unit-test-load': pass # Keep the result, but do no more. elif hasattr(result,'init'): try: # Indicate success only if init_result is True. init_result = result.init() if init_result not in (True,False): g.error('Error: %s.init did not return a bool' % (moduleName)) if init_result: self.loadedModules[moduleName] = result self.loadedModulesFilesDict[moduleName] = g.app.config.enabledPluginsFileName else: if verbose and not g.app.initing: g.error('loadOnePlugin: failed to load module',moduleName) result = None except Exception: g.error('exception loading plugin') g.es_exception() result = None else: # No top-level init function. # Guess that the module was loaded correctly, # but do *not* load the plugin if we are unit testing. if g.app.unitTesting: result = None self.loadedModules[moduleName] = None else: g.trace('no init()',moduleName) self.loadedModules[moduleName] = result self.loadingModuleNameStack.pop() if g.app.batchMode or g.app.inBridge: # or g.unitTesting pass elif result: if trace or verbose: g.blue('loadOnePlugin: loaded',moduleName) else: if trace or self.warn_on_failure or (verbose and not g.app.initing): if trace or tag == 'open0': g.error('loadOnePlugin: can not load enabled plugin:',moduleName) return result
# outside the event loop. It might be possible to do this in # an idle-time handler. # # If it is possible several more settings would be possible. #@-<< to do >> #@+<< imports >> #@+node:ekr.20080201143145.3: ** << imports >> import leo.core.leoGlobals as g import sys try: import IPython.ipapi import_ok = True except ImportError: g.error('ipython plugin: can not import IPython.ipapi') import_ok = False except SyntaxError: g.error('ipython plugin: syntax error importing IPython.ipapi') import_ok = False #@-<< imports >> # Globals # IPython IPApi instance. Global, because only one can exist through the whole leo session gIP = None #@+others #@+node:ekr.20080201144219: ** Module-level functions