How do you put a save hook into wing?


417
views
1
8 months ago by
Wanting to add yapf formatting on save, but I need a way to capture the save event, run the formatter, update the buffer, then call the base save.

I see mentions about a pre-save event, but not finding any details anywhere.
Community: Wing Python IDE

2 Answers


2
8 months ago by
Here's a different approach that does hook up to presave to replace the contents of the editor at save time, just before saving, with the output from yapf:

import subprocess
import wingapi

def run_yapf(doc=wingapi.kArgDocument):
  
  # Set to non-None to use an uninstalled copy of yapf
  kYapfDir = None
  #kYapfDir = '/Users/jpe/Documents/tmp/yapf'
  
  proj = wingapi.gApplication.GetProject()
  pyexec = proj.GetPythonExecutable(doc.GetFilename())
  
  orig_text = doc.GetText()
  
  argv = [pyexec, '-m', 'yapf']
  process = subprocess.Popen(argv, cwd=kYapfDir, stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  from_yapf, error_output = process.communicate(orig_text)
  if from_yapf != orig_text:
    doc.SetText(from_yapf)

def _connect_to_document(doc):
  def _on_presave(filename, encoding):
    # Called for autosave w/ filename set to non-None
    if filename is not None:
      return
    
    if doc.GetMimeType() == 'text/x-python':
      run_yapf(doc)

  connect_id = doc.Connect('presave', _on_presave)

def _init():
  wingapi.gApplication.Connect('document-open', _connect_to_document)
  for doc in wingapi.gApplication.GetOpenDocuments():
    _connect_to_document(doc)
    
_init()
​
I'm assuming at this point any possibility of undo would be lost past the save wouldn't it.
written 4 months ago by Mark Jones  
Yea, I think so but instead of calling SetText() on the doc you could call SetSelection() on the CAPIEditor instance to select all the text and then reach through the API with ed.fEditor._fScint.replace_sel(from_yapf) where ed is the instance of CAPIEditor.  Then one undo should return you to the pre-yapf text, but of course saving again would replace it again, etc, so more would be needed to allow saving without the replacement.  Personally, I'd rather have a way to run yapf on the file on demand and not with every save.  Or more likely I'd just not use things like yapf since Python is extremely readable regardless of details of the formatting.
written 4 months ago by Wingware Support  
0
8 months ago by
You want the save-point signal on the CAPIDocument.  Something like this:

import wingapi

def _connect_to_document(doc):
  def _on_modified(savepoint):
    if not savepoint:
      return
    # Execute yapf here, possibly with wingapi.gApplication.AsyncExecuteCommandLine
  connect_id = doc.Connect('save-point', _on_modified)

def _init():
  wingapi.gApplication.Connect('document-open', _connect_to_document)
  for doc in wingapi.gApplication.GetOpenDocuments():
    _connect_to_document(doc)
    
_init()
​
This approach assumed that yapf would run and change the file on disk, and Wing would reload the changed file automatically afterward.  The other answer above is probably better, and is more complete in any case.
written 8 months ago by Wingware Support  
Please login to add an answer/comment or follow this question.

Similar posts:
Search »