123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832 |
- # A general purpose MFC CCtrlView view that uses Scintilla.
-
- import array
- import os
- import re
- import string
- import struct
- import sys
-
- import __main__ # for attribute lookup
- import afxres
- import win32con
- import win32ui
- from pywin.mfc import dialog, docview
-
- from . import IDLEenvironment # IDLE emulation.
- from . import bindings, control, keycodes, scintillacon
-
- PRINTDLGORD = 1538
- IDC_PRINT_MAG_EDIT = 1010
- EM_FORMATRANGE = win32con.WM_USER + 57
-
- wordbreaks = "._" + string.ascii_uppercase + string.ascii_lowercase + string.digits
-
- patImport = re.compile("import (?P<name>.*)")
-
- _event_commands = [
- # File menu
- "win32ui.ID_FILE_LOCATE",
- "win32ui.ID_FILE_CHECK",
- "afxres.ID_FILE_CLOSE",
- "afxres.ID_FILE_NEW",
- "afxres.ID_FILE_OPEN",
- "afxres.ID_FILE_SAVE",
- "afxres.ID_FILE_SAVE_AS",
- "win32ui.ID_FILE_SAVE_ALL",
- # Edit menu
- "afxres.ID_EDIT_UNDO",
- "afxres.ID_EDIT_REDO",
- "afxres.ID_EDIT_CUT",
- "afxres.ID_EDIT_COPY",
- "afxres.ID_EDIT_PASTE",
- "afxres.ID_EDIT_SELECT_ALL",
- "afxres.ID_EDIT_FIND",
- "afxres.ID_EDIT_REPEAT",
- "afxres.ID_EDIT_REPLACE",
- # View menu
- "win32ui.ID_VIEW_WHITESPACE",
- "win32ui.ID_VIEW_FIXED_FONT",
- "win32ui.ID_VIEW_BROWSE",
- "win32ui.ID_VIEW_INTERACTIVE",
- # Window menu
- "afxres.ID_WINDOW_ARRANGE",
- "afxres.ID_WINDOW_CASCADE",
- "afxres.ID_WINDOW_NEW",
- "afxres.ID_WINDOW_SPLIT",
- "afxres.ID_WINDOW_TILE_HORZ",
- "afxres.ID_WINDOW_TILE_VERT",
- # Others
- "afxres.ID_APP_EXIT",
- "afxres.ID_APP_ABOUT",
- ]
-
- _extra_event_commands = [
- ("EditDelete", afxres.ID_EDIT_CLEAR),
- ("LocateModule", win32ui.ID_FILE_LOCATE),
- ("GotoLine", win32ui.ID_EDIT_GOTO_LINE),
- ("DbgBreakpointToggle", win32ui.IDC_DBG_ADD),
- ("DbgGo", win32ui.IDC_DBG_GO),
- ("DbgStepOver", win32ui.IDC_DBG_STEPOVER),
- ("DbgStep", win32ui.IDC_DBG_STEP),
- ("DbgStepOut", win32ui.IDC_DBG_STEPOUT),
- ("DbgBreakpointClearAll", win32ui.IDC_DBG_CLEAR),
- ("DbgClose", win32ui.IDC_DBG_CLOSE),
- ]
-
- event_commands = []
-
-
- def _CreateEvents():
- for name in _event_commands:
- val = eval(name)
- name_parts = name.split("_")[1:]
- name_parts = [p.capitalize() for p in name_parts]
- event = "".join(name_parts)
- event_commands.append((event, val))
- for name, id in _extra_event_commands:
- event_commands.append((name, id))
-
-
- _CreateEvents()
- del _event_commands
- del _extra_event_commands
-
- command_reflectors = [
- (win32ui.ID_EDIT_UNDO, win32con.WM_UNDO),
- (win32ui.ID_EDIT_REDO, scintillacon.SCI_REDO),
- (win32ui.ID_EDIT_CUT, win32con.WM_CUT),
- (win32ui.ID_EDIT_COPY, win32con.WM_COPY),
- (win32ui.ID_EDIT_PASTE, win32con.WM_PASTE),
- (win32ui.ID_EDIT_CLEAR, win32con.WM_CLEAR),
- (win32ui.ID_EDIT_SELECT_ALL, scintillacon.SCI_SELECTALL),
- ]
-
-
- def DoBraceMatch(control):
- curPos = control.SCIGetCurrentPos()
- charBefore = " "
- if curPos:
- charBefore = control.SCIGetCharAt(curPos - 1)
- charAt = control.SCIGetCharAt(curPos)
- braceAtPos = braceOpposite = -1
- if charBefore in "[](){}":
- braceAtPos = curPos - 1
- if braceAtPos == -1:
- if charAt in "[](){}":
- braceAtPos = curPos
- if braceAtPos != -1:
- braceOpposite = control.SCIBraceMatch(braceAtPos, 0)
- if braceAtPos != -1 and braceOpposite == -1:
- control.SCIBraceBadHighlight(braceAtPos)
- else:
- # either clear them both or set them both.
- control.SCIBraceHighlight(braceAtPos, braceOpposite)
-
-
- def _get_class_attributes(ob):
- # Recurse into base classes looking for attributes
- items = []
- try:
- items = items + dir(ob)
- for i in ob.__bases__:
- for item in _get_class_attributes(i):
- if item not in items:
- items.append(item)
- except AttributeError:
- pass
- return items
-
-
- # Supposed to look like an MFC CEditView, but
- # also supports IDLE extensions and other source code generic features.
- class CScintillaView(docview.CtrlView, control.CScintillaColorEditInterface):
- def __init__(self, doc):
- docview.CtrlView.__init__(
- self,
- doc,
- "Scintilla",
- win32con.WS_CHILD
- | win32con.WS_VSCROLL
- | win32con.WS_HSCROLL
- | win32con.WS_CLIPCHILDREN
- | win32con.WS_VISIBLE,
- )
- self._tabWidth = (
- 8 # Mirror of what we send to Scintilla - never change this directly
- )
- self.bAutoCompleteAttributes = 1
- self.bShowCallTips = 1
- self.bMatchBraces = 0 # Editor option will default this to true later!
- self.bindings = bindings.BindingsManager(self)
-
- self.idle = IDLEenvironment.IDLEEditorWindow(self)
- self.idle.IDLEExtension("AutoExpand")
- # SendScintilla is called so frequently it is worth optimizing.
- self.SendScintilla = self._obj_.SendMessage
-
- def _MakeColorizer(self):
- ext = os.path.splitext(self.GetDocument().GetPathName())[1]
- from . import formatter
-
- return formatter.BuiltinPythonSourceFormatter(self, ext)
-
- # def SendScintilla(self, msg, w=0, l=0):
- # return self._obj_.SendMessage(msg, w, l)
-
- def SCISetTabWidth(self, width):
- # I need to remember the tab-width for the AutoIndent extension. This may go.
- self._tabWidth = width
- control.CScintillaEditInterface.SCISetTabWidth(self, width)
-
- def GetTabWidth(self):
- return self._tabWidth
-
- def HookHandlers(self):
- # Create events for all the menu names.
- for name, val in event_commands:
- # handler = lambda id, code, tosend=val, parent=parent: parent.OnCommand(tosend, 0) and 0
- self.bindings.bind(name, None, cid=val)
-
- # Hook commands that do nothing other than send Scintilla messages.
- for command, reflection in command_reflectors:
- handler = (
- lambda id, code, ss=self.SendScintilla, tosend=reflection: ss(tosend)
- and 0
- )
- self.HookCommand(handler, command)
-
- self.HookCommand(self.OnCmdViewWS, win32ui.ID_VIEW_WHITESPACE)
- self.HookCommandUpdate(self.OnUpdateViewWS, win32ui.ID_VIEW_WHITESPACE)
- self.HookCommand(
- self.OnCmdViewIndentationGuides, win32ui.ID_VIEW_INDENTATIONGUIDES
- )
- self.HookCommandUpdate(
- self.OnUpdateViewIndentationGuides, win32ui.ID_VIEW_INDENTATIONGUIDES
- )
- self.HookCommand(self.OnCmdViewRightEdge, win32ui.ID_VIEW_RIGHT_EDGE)
- self.HookCommandUpdate(self.OnUpdateViewRightEdge, win32ui.ID_VIEW_RIGHT_EDGE)
- self.HookCommand(self.OnCmdViewEOL, win32ui.ID_VIEW_EOL)
- self.HookCommandUpdate(self.OnUpdateViewEOL, win32ui.ID_VIEW_EOL)
- self.HookCommand(self.OnCmdViewFixedFont, win32ui.ID_VIEW_FIXED_FONT)
- self.HookCommandUpdate(self.OnUpdateViewFixedFont, win32ui.ID_VIEW_FIXED_FONT)
- self.HookCommand(self.OnCmdFileLocate, win32ui.ID_FILE_LOCATE)
- self.HookCommand(self.OnCmdEditFind, win32ui.ID_EDIT_FIND)
- self.HookCommand(self.OnCmdEditRepeat, win32ui.ID_EDIT_REPEAT)
- self.HookCommand(self.OnCmdEditReplace, win32ui.ID_EDIT_REPLACE)
- self.HookCommand(self.OnCmdGotoLine, win32ui.ID_EDIT_GOTO_LINE)
- self.HookCommand(self.OnFilePrint, afxres.ID_FILE_PRINT)
- self.HookCommand(self.OnFilePrint, afxres.ID_FILE_PRINT_DIRECT)
- self.HookCommand(self.OnFilePrintPreview, win32ui.ID_FILE_PRINT_PREVIEW)
- # Key bindings.
- self.HookMessage(self.OnKeyDown, win32con.WM_KEYDOWN)
- self.HookMessage(self.OnKeyDown, win32con.WM_SYSKEYDOWN)
- # Hook wheeley mouse events
- # self.HookMessage(self.OnMouseWheel, win32con.WM_MOUSEWHEEL)
- self.HookFormatter()
-
- def OnInitialUpdate(self):
- doc = self.GetDocument()
-
- # Enable Unicode
- self.SendScintilla(scintillacon.SCI_SETCODEPAGE, scintillacon.SC_CP_UTF8, 0)
- self.SendScintilla(scintillacon.SCI_SETKEYSUNICODE, 1, 0)
-
- # Create margins
- self.SendScintilla(
- scintillacon.SCI_SETMARGINTYPEN, 1, scintillacon.SC_MARGIN_SYMBOL
- )
- self.SendScintilla(scintillacon.SCI_SETMARGINMASKN, 1, 0xF)
- self.SendScintilla(
- scintillacon.SCI_SETMARGINTYPEN, 2, scintillacon.SC_MARGIN_SYMBOL
- )
- self.SendScintilla(
- scintillacon.SCI_SETMARGINMASKN, 2, scintillacon.SC_MASK_FOLDERS
- )
- self.SendScintilla(scintillacon.SCI_SETMARGINSENSITIVEN, 2, 1)
-
- self.GetDocument().HookViewNotifications(
- self
- ) # is there an MFC way to grab this?
- self.HookHandlers()
-
- # Load the configuration information.
- self.OnWinIniChange(None)
-
- self.SetSel()
-
- self.GetDocument().FinalizeViewCreation(
- self
- ) # is there an MFC way to grab this?
-
- def _GetSubConfigNames(self):
- return None # By default we use only sections without sub-sections.
-
- def OnWinIniChange(self, section=None):
- self.bindings.prepare_configure()
- try:
- self.DoConfigChange()
- finally:
- self.bindings.complete_configure()
-
- def DoConfigChange(self):
- # Bit of a hack I dont kow what to do about - these should be "editor options"
- from pywin.framework.editor import GetEditorOption
-
- self.bAutoCompleteAttributes = GetEditorOption("Autocomplete Attributes", 1)
- self.bShowCallTips = GetEditorOption("Show Call Tips", 1)
- # Update the key map and extension data.
- configManager.configure(self, self._GetSubConfigNames())
- if configManager.last_error:
- win32ui.MessageBox(configManager.last_error, "Configuration Error")
- self.bMatchBraces = GetEditorOption("Match Braces", 1)
- self.ApplyFormattingStyles(1)
-
- def OnDestroy(self, msg):
- self.bindings.close()
- self.bindings = None
- self.idle.close()
- self.idle = None
- control.CScintillaColorEditInterface.close(self)
- return docview.CtrlView.OnDestroy(self, msg)
-
- def OnMouseWheel(self, msg):
- zDelta = msg[2] >> 16
- vpos = self.GetScrollPos(win32con.SB_VERT)
- vpos = vpos - zDelta / 40 # 3 lines per notch
- self.SetScrollPos(win32con.SB_VERT, vpos)
- self.SendScintilla(
- win32con.WM_VSCROLL, (vpos << 16) | win32con.SB_THUMBPOSITION, 0
- )
-
- def OnBraceMatch(self, std, extra):
- if not self.bMatchBraces:
- return
- DoBraceMatch(self)
-
- def OnNeedShown(self, std, extra):
- notify = self.SCIUnpackNotifyMessage(extra)
- # OnNeedShown is called before an edit operation when
- # text is folded (as it is possible the text insertion will happen
- # in a folded region.) As this happens _before_ the insert,
- # we ignore the length (if we are at EOF, pos + length may
- # actually be beyond the end of buffer)
- self.EnsureCharsVisible(notify.position)
-
- def EnsureCharsVisible(self, start, end=None):
- if end is None:
- end = start
- lineStart = self.LineFromChar(min(start, end))
- lineEnd = self.LineFromChar(max(start, end))
- while lineStart <= lineEnd:
- self.SCIEnsureVisible(lineStart)
- lineStart = lineStart + 1
-
- # Helper to add an event to a menu.
- def AppendMenu(self, menu, text="", event=None, flags=None, checked=0):
- if event is None:
- assert flags is not None, "No event or custom flags!"
- cmdid = 0
- else:
- cmdid = self.bindings.get_command_id(event)
- if cmdid is None:
- # No event of that name - no point displaying it.
- print(
- 'View.AppendMenu(): Unknown event "%s" specified for menu text "%s" - ignored'
- % (event, text)
- )
- return
- keyname = configManager.get_key_binding(event, self._GetSubConfigNames())
- if keyname is not None:
- text = text + "\t" + keyname
- if flags is None:
- flags = win32con.MF_STRING | win32con.MF_ENABLED
- if checked:
- flags = flags | win32con.MF_CHECKED
- menu.AppendMenu(flags, cmdid, text)
-
- def OnKeyDown(self, msg):
- return self.bindings.fire_key_event(msg)
-
- def GotoEndOfFileEvent(self, event):
- self.SetSel(-1)
-
- def KeyDotEvent(self, event):
- ## Don't trigger autocomplete if any text is selected
- s, e = self.GetSel()
- if s != e:
- return 1
- self.SCIAddText(".")
- if self.bAutoCompleteAttributes:
- self._AutoComplete()
-
- # View Whitespace/EOL/Indentation UI.
-
- def OnCmdViewWS(self, cmd, code): # Handle the menu command
- viewWS = self.SCIGetViewWS()
- self.SCISetViewWS(not viewWS)
-
- def OnUpdateViewWS(self, cmdui): # Update the tick on the UI.
- cmdui.SetCheck(self.SCIGetViewWS())
- cmdui.Enable()
-
- def OnCmdViewIndentationGuides(self, cmd, code): # Handle the menu command
- viewIG = self.SCIGetIndentationGuides()
- self.SCISetIndentationGuides(not viewIG)
-
- def OnUpdateViewIndentationGuides(self, cmdui): # Update the tick on the UI.
- cmdui.SetCheck(self.SCIGetIndentationGuides())
- cmdui.Enable()
-
- def OnCmdViewRightEdge(self, cmd, code): # Handle the menu command
- if self.SCIGetEdgeMode() == scintillacon.EDGE_NONE:
- mode = scintillacon.EDGE_BACKGROUND
- else:
- mode = scintillacon.EDGE_NONE
- self.SCISetEdgeMode(mode)
-
- def OnUpdateViewRightEdge(self, cmdui): # Update the tick on the UI.
- cmdui.SetCheck(self.SCIGetEdgeMode() != scintillacon.EDGE_NONE)
- cmdui.Enable()
-
- def OnCmdViewEOL(self, cmd, code): # Handle the menu command
- viewEOL = self.SCIGetViewEOL()
- self.SCISetViewEOL(not viewEOL)
-
- def OnUpdateViewEOL(self, cmdui): # Update the tick on the UI.
- cmdui.SetCheck(self.SCIGetViewEOL())
- cmdui.Enable()
-
- def OnCmdViewFixedFont(self, cmd, code): # Handle the menu command
- self._GetColorizer().bUseFixed = not self._GetColorizer().bUseFixed
- self.ApplyFormattingStyles(0)
- # Ensure the selection is visible!
- self.ScrollCaret()
-
- def OnUpdateViewFixedFont(self, cmdui): # Update the tick on the UI.
- c = self._GetColorizer()
- if c is not None:
- cmdui.SetCheck(c.bUseFixed)
- cmdui.Enable(c is not None)
-
- def OnCmdEditFind(self, cmd, code):
- from . import find
-
- find.ShowFindDialog()
-
- def OnCmdEditRepeat(self, cmd, code):
- from . import find
-
- find.FindNext()
-
- def OnCmdEditReplace(self, cmd, code):
- from . import find
-
- find.ShowReplaceDialog()
-
- def OnCmdFileLocate(self, cmd, id):
- line = self.GetLine().strip()
- import pywin.framework.scriptutils
-
- m = patImport.match(line)
- if m:
- # Module name on this line - locate that!
- modName = m.group("name")
- fileName = pywin.framework.scriptutils.LocatePythonFile(modName)
- if fileName is None:
- win32ui.SetStatusText("Can't locate module %s" % modName)
- return 1 # Let the default get it.
- else:
- win32ui.GetApp().OpenDocumentFile(fileName)
- else:
- # Just to a "normal" locate - let the default handler get it.
- return 1
- return 0
-
- def OnCmdGotoLine(self, cmd, id):
- try:
- lineNo = int(input("Enter Line Number")) - 1
- except (ValueError, KeyboardInterrupt):
- return 0
- self.SCIEnsureVisible(lineNo)
- self.SCIGotoLine(lineNo)
- return 0
-
- def SaveTextFile(self, filename, encoding=None):
- doc = self.GetDocument()
- doc._SaveTextToFile(self, filename, encoding=encoding)
- doc.SetModifiedFlag(0)
- return 1
-
- def _AutoComplete(self):
- def list2dict(l):
- ret = {}
- for i in l:
- ret[i] = None
- return ret
-
- self.SCIAutoCCancel() # Cancel old auto-complete lists.
- # First try and get an object without evaluating calls
- ob = self._GetObjectAtPos(bAllowCalls=0)
- # If that failed, try and process call or indexing to get the object.
- if ob is None:
- ob = self._GetObjectAtPos(bAllowCalls=1)
- items_dict = {}
- if ob is not None:
- try: # Catch unexpected errors when fetching attribute names from the object
- # extra attributes of win32ui objects
- if hasattr(ob, "_obj_"):
- try:
- items_dict.update(list2dict(dir(ob._obj_)))
- except AttributeError:
- pass # object has no __dict__
-
- # normal attributes
- try:
- items_dict.update(list2dict(dir(ob)))
- except AttributeError:
- pass # object has no __dict__
- if hasattr(ob, "__class__"):
- items_dict.update(list2dict(_get_class_attributes(ob.__class__)))
- # The object may be a COM object with typelib support - lets see if we can get its props.
- # (contributed by Stefan Migowsky)
- try:
- # Get the automation attributes
- items_dict.update(ob.__class__._prop_map_get_)
- # See if there is an write only property
- # could be optimized
- items_dict.update(ob.__class__._prop_map_put_)
- # append to the already evaluated list
- except AttributeError:
- pass
- # The object might be a pure COM dynamic dispatch with typelib support - lets see if we can get its props.
- if hasattr(ob, "_oleobj_"):
- try:
- for iTI in range(0, ob._oleobj_.GetTypeInfoCount()):
- typeInfo = ob._oleobj_.GetTypeInfo(iTI)
- self._UpdateWithITypeInfo(items_dict, typeInfo)
- except:
- pass
- except:
- win32ui.SetStatusText(
- "Error attempting to get object attributes - %s"
- % (repr(sys.exc_info()[0]),)
- )
-
- # ensure all keys are strings.
- items = [str(k) for k in items_dict.keys()]
- # All names that start with "_" go!
- items = [k for k in items if not k.startswith("_")]
-
- if not items:
- # Heuristics a-la AutoExpand
- # The idea is to find other usages of the current binding
- # and assume, that it refers to the same object (or at least,
- # to an object of the same type)
- # Contributed by Vadim Chugunov [vadimch@yahoo.com]
- left, right = self._GetWordSplit()
- if left == "": # Ignore standalone dots
- return None
- # We limit our search to the current class, if that
- # information is available
- minline, maxline, curclass = self._GetClassInfoFromBrowser()
- endpos = self.LineIndex(maxline)
- text = self.GetTextRange(self.LineIndex(minline), endpos)
- try:
- l = re.findall(r"\b" + left + "\.\w+", text)
- except re.error:
- # parens etc may make an invalid RE, but this code wouldnt
- # benefit even if the RE did work :-)
- l = []
- prefix = len(left) + 1
- unique = {}
- for li in l:
- unique[li[prefix:]] = 1
- # Assuming traditional usage of self...
- if curclass and left == "self":
- self._UpdateWithClassMethods(unique, curclass)
-
- items = [
- word for word in unique.keys() if word[:2] != "__" or word[-2:] != "__"
- ]
- # Ignore the word currently to the right of the dot - probably a red-herring.
- try:
- items.remove(right[1:])
- except ValueError:
- pass
- if items:
- items.sort()
- self.SCIAutoCSetAutoHide(0)
- self.SCIAutoCShow(items)
-
- def _UpdateWithITypeInfo(self, items_dict, typeInfo):
- import pythoncom
-
- typeInfos = [typeInfo]
- # suppress IDispatch and IUnknown methods
- inspectedIIDs = {pythoncom.IID_IDispatch: None}
-
- while len(typeInfos) > 0:
- typeInfo = typeInfos.pop()
- typeAttr = typeInfo.GetTypeAttr()
-
- if typeAttr.iid not in inspectedIIDs:
- inspectedIIDs[typeAttr.iid] = None
- for iFun in range(0, typeAttr.cFuncs):
- funDesc = typeInfo.GetFuncDesc(iFun)
- funName = typeInfo.GetNames(funDesc.memid)[0]
- if funName not in items_dict:
- items_dict[funName] = None
-
- # Inspect the type info of all implemented types
- # E.g. IShellDispatch5 implements IShellDispatch4 which implements IShellDispatch3 ...
- for iImplType in range(0, typeAttr.cImplTypes):
- iRefType = typeInfo.GetRefTypeOfImplType(iImplType)
- refTypeInfo = typeInfo.GetRefTypeInfo(iRefType)
- typeInfos.append(refTypeInfo)
-
- # TODO: This is kinda slow. Probably need some kind of cache
- # here that is flushed upon file save
- # Or maybe we don't need the superclass methods at all ?
- def _UpdateWithClassMethods(self, dict, classinfo):
- if not hasattr(classinfo, "methods"):
- # No 'methods' - probably not what we think it is.
- return
- dict.update(classinfo.methods)
- for super in classinfo.super:
- if hasattr(super, "methods"):
- self._UpdateWithClassMethods(dict, super)
-
- # Find which class definition caret is currently in and return
- # indexes of the the first and the last lines of that class definition
- # Data is obtained from module browser (if enabled)
- def _GetClassInfoFromBrowser(self, pos=-1):
- minline = 0
- maxline = self.GetLineCount() - 1
- doc = self.GetParentFrame().GetActiveDocument()
- browser = None
- try:
- if doc is not None:
- browser = doc.GetAllViews()[1]
- except IndexError:
- pass
- if browser is None:
- return (minline, maxline, None) # Current window has no browser
- if not browser.list:
- return (minline, maxline, None) # Not initialized
- path = self.GetDocument().GetPathName()
- if not path:
- return (minline, maxline, None) # No current path
-
- import pywin.framework.scriptutils
-
- curmodule, path = pywin.framework.scriptutils.GetPackageModuleName(path)
- try:
- clbrdata = browser.list.root.clbrdata
- except AttributeError:
- return (minline, maxline, None) # No class data for this module.
- curline = self.LineFromChar(pos)
- curclass = None
- # Find out which class we are in
- for item in clbrdata.values():
- if item.module == curmodule:
- item_lineno = (
- item.lineno - 1
- ) # Scintilla counts lines from 0, whereas pyclbr - from 1
- if minline < item_lineno <= curline:
- minline = item_lineno
- curclass = item
- if curline < item_lineno < maxline:
- maxline = item_lineno
- return (minline, maxline, curclass)
-
- def _GetObjectAtPos(self, pos=-1, bAllowCalls=0):
- left, right = self._GetWordSplit(pos, bAllowCalls)
- if left: # It is an attribute lookup
- # How is this for a hack!
- namespace = sys.modules.copy()
- namespace.update(__main__.__dict__)
- # Get the debugger's context.
- try:
- from pywin.framework import interact
-
- if interact.edit is not None and interact.edit.currentView is not None:
- globs, locs = interact.edit.currentView.GetContext()[:2]
- if globs:
- namespace.update(globs)
- if locs:
- namespace.update(locs)
- except ImportError:
- pass
- try:
- return eval(left, namespace)
- except:
- pass
- return None
-
- def _GetWordSplit(self, pos=-1, bAllowCalls=0):
- if pos == -1:
- pos = self.GetSel()[0] - 1 # Character before current one
- limit = self.GetTextLength()
- before = []
- after = []
- index = pos - 1
- wordbreaks_use = wordbreaks
- if bAllowCalls:
- wordbreaks_use = wordbreaks_use + "()[]"
- while index >= 0:
- char = self.SCIGetCharAt(index)
- if char not in wordbreaks_use:
- break
- before.insert(0, char)
- index = index - 1
- index = pos
- while index <= limit:
- char = self.SCIGetCharAt(index)
- if char not in wordbreaks_use:
- break
- after.append(char)
- index = index + 1
- return "".join(before), "".join(after)
-
- def OnPrepareDC(self, dc, pInfo):
- # print "OnPrepareDC for page", pInfo.GetCurPage(), "of", pInfo.GetFromPage(), "to", pInfo.GetToPage(), ", starts=", self.starts
- if dc.IsPrinting():
- # Check if we are beyond the end.
- # (only do this when actually printing, else messes up print preview!)
- if not pInfo.GetPreview() and self.starts is not None:
- prevPage = pInfo.GetCurPage() - 1
- if prevPage > 0 and self.starts[prevPage] >= self.GetTextLength():
- # All finished.
- pInfo.SetContinuePrinting(0)
- return
- dc.SetMapMode(win32con.MM_TEXT)
-
- def OnPreparePrinting(self, pInfo):
- flags = (
- win32ui.PD_USEDEVMODECOPIES | win32ui.PD_ALLPAGES | win32ui.PD_NOSELECTION
- ) # Dont support printing just a selection.
- # NOTE: Custom print dialogs are stopping the user's values from coming back :-(
- # self.prtDlg = PrintDialog(pInfo, PRINTDLGORD, flags)
- # pInfo.SetPrintDialog(self.prtDlg)
- pInfo.SetMinPage(1)
- # max page remains undefined for now.
- pInfo.SetFromPage(1)
- pInfo.SetToPage(1)
- ret = self.DoPreparePrinting(pInfo)
- return ret
-
- def OnBeginPrinting(self, dc, pInfo):
- self.starts = None
- return self._obj_.OnBeginPrinting(dc, pInfo)
-
- def CalculatePageRanges(self, dc, pInfo):
- # Calculate page ranges and max page
- self.starts = {0: 0}
- metrics = dc.GetTextMetrics()
- left, top, right, bottom = pInfo.GetDraw()
- # Leave space at the top for the header.
- rc = (left, top + int((9 * metrics["tmHeight"]) / 2), right, bottom)
- pageStart = 0
- maxPage = 0
- textLen = self.GetTextLength()
- while pageStart < textLen:
- pageStart = self.FormatRange(dc, pageStart, textLen, rc, 0)
- maxPage = maxPage + 1
- self.starts[maxPage] = pageStart
- # And a sentinal for one page past the end
- self.starts[maxPage + 1] = textLen
- # When actually printing, maxPage doesnt have any effect at this late state.
- # but is needed to make the Print Preview work correctly.
- pInfo.SetMaxPage(maxPage)
-
- def OnFilePrintPreview(self, *arg):
- self._obj_.OnFilePrintPreview()
-
- def OnFilePrint(self, *arg):
- self._obj_.OnFilePrint()
-
- def FormatRange(self, dc, pageStart, lengthDoc, rc, draw):
- """
- typedef struct _formatrange {
- HDC hdc;
- HDC hdcTarget;
- RECT rc;
- RECT rcPage;
- CHARRANGE chrg;} FORMATRANGE;
- """
- fmt = "PPIIIIIIIIll"
- hdcRender = dc.GetHandleOutput()
- hdcFormat = dc.GetHandleAttrib()
- fr = struct.pack(
- fmt,
- hdcRender,
- hdcFormat,
- rc[0],
- rc[1],
- rc[2],
- rc[3],
- rc[0],
- rc[1],
- rc[2],
- rc[3],
- pageStart,
- lengthDoc,
- )
- nextPageStart = self.SendScintilla(EM_FORMATRANGE, draw, fr)
- return nextPageStart
-
- def OnPrint(self, dc, pInfo):
- metrics = dc.GetTextMetrics()
- # print "dev", w, h, l, metrics['tmAscent'], metrics['tmDescent']
- if self.starts is None:
- self.CalculatePageRanges(dc, pInfo)
- pageNum = pInfo.GetCurPage() - 1
- # Setup the header of the page - docname on left, pagenum on right.
- doc = self.GetDocument()
- cxChar = metrics["tmAveCharWidth"]
- cyChar = metrics["tmHeight"]
- left, top, right, bottom = pInfo.GetDraw()
- dc.TextOut(0, 2 * cyChar, doc.GetTitle())
- pagenum_str = win32ui.LoadString(afxres.AFX_IDS_PRINTPAGENUM) % (pageNum + 1,)
- dc.SetTextAlign(win32con.TA_RIGHT)
- dc.TextOut(right, 2 * cyChar, pagenum_str)
- dc.SetTextAlign(win32con.TA_LEFT)
- top = top + int((7 * cyChar) / 2)
- dc.MoveTo(left, top)
- dc.LineTo(right, top)
- top = top + cyChar
- rc = (left, top, right, bottom)
- nextPageStart = self.FormatRange(
- dc, self.starts[pageNum], self.starts[pageNum + 1], rc, 1
- )
-
-
- def LoadConfiguration():
- global configManager
- # Bit of a hack I dont kow what to do about?
- from .config import ConfigManager
-
- configName = rc = win32ui.GetProfileVal("Editor", "Keyboard Config", "default")
- configManager = ConfigManager(configName)
- if configManager.last_error:
- bTryDefault = 0
- msg = "Error loading configuration '%s'\n\n%s" % (
- configName,
- configManager.last_error,
- )
- if configName != "default":
- msg = msg + "\n\nThe default configuration will be loaded."
- bTryDefault = 1
- win32ui.MessageBox(msg)
- if bTryDefault:
- configManager = ConfigManager("default")
- if configManager.last_error:
- win32ui.MessageBox(
- "Error loading configuration 'default'\n\n%s"
- % (configManager.last_error)
- )
-
-
- configManager = None
- LoadConfiguration()
|