Ask Your Question
1

How do you put a save hook into wing?

asked 2017-11-07 13:38:00 -0600

Mark Jones gravatar image

updated 2019-03-13 10:06:52 -0600

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.

edit retag flag offensive close merge delete

2 Answers

Sort by » oldest newest most voted
1

answered 2017-11-08 07:41:00 -0600

updated 2019-03-07 08:01:36 -0600

Wingware Admin gravatar image

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()
edit flag offensive delete link more

Comments

I'm assuming at this point any possibility of undo would be lost past the save wouldn't it.

Mark Jones gravatar imageMark Jones ( 2018-02-23 14:38:00 -0600 )edit

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.

Wingware Support gravatar imageWingware Support ( 2018-02-23 14:46:00 -0600 )edit
0

answered 2017-11-07 16:05:00 -0600

updated 2019-03-07 08:01:08 -0600

Wingware Admin gravatar image

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()
edit flag offensive delete link more

Comments

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.

Wingware Support gravatar imageWingware Support ( 2017-11-08 07:43:00 -0600 )edit

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools

2 followers

Stats

Asked: 2017-11-07 13:38:00 -0600

Seen: 95 times

Last updated: Mar 07