Revision history [back]
Okay, could you help me take a look at this plugin I wrote? It works fine, but there is one issue. For example, if the header information has 5 lines, when the scrollbar scrolls to exactly show the 5th line, activating the plugin to update the header information will cause the scrollbar to automatically scroll to display the entire header, instead of staying at the 5th line position. If the plugin is activated to update when the header is not visible, there is no problem.
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
######################################################################
########################### yang's header ############################
######################################################################
# File: autoheader.py #
# Create Data: 2026/02/28 11:22:14 #
# Author: xxxx #
# Email: xxxx@hotmail.com #
# Last Modified: 2026/05/22 11:52:19 #
# Modified By: xxxXx #
# Copyright (c) 2025 xxxx Culture Media Co., Ltd #
######################################################################
import wingapi
import copy
import datetime
import platform
import subprocess
from pathlib import Path
app = wingapi.gApplication
_plugin_id = [None]
_preSaveId = [None]
_fileType = ['.py']
class header():
def __init__(self, doc):
# chars
self.commentChar = "#"
self.aroundChar = " "
self.filler = " " # space
# attributes
self.docObj = doc
self.title = "Comment"
self.fileNameLabel = "File:"
self.fileName = ""
self.fullFileName = ""
self.emailLabel = "Email:"
self.email = ""
self.createTimeLabel = "Create Data:"
self.modifyDataLabel = "Last Modified:"
self.modifyByLabel = "Modified By:"
self.modifyBy = ""
self.authorLabel = "Author:"
self.author = ""
self.copyRightLine = ""
# lines
self.lines = {"preLines": [], "startLines": [], "titleLines": [], "bodyLines": [], "endLines": [], "postLines": [], }
self.actualLines = {}
self.bodyLines = []
# controls
self.maxChar = 70 # if less than bodyLine length, use length of bodyLine.
self.bodyLineMax = self.maxChar
self.withFullName = False
self.lastSpaceLineCount = 2
self.withStartLine = True
self.withTitleLine = True
def setheader(self):
self.updateHeader()
f = self.docObj.GetAsFileObject()
charCount = 0
# check preLines
for preLine in self.actualLines["preLines"]:
docLine = f.readline()
if docLine.rstrip("\n") != preLine:
print("preLines is different, insert all.")
self.docObj.InsertChars(0, str(self))
return True
charCount += len(docLine)
# check startLines
if self.withStartLine:
for startLine in self.actualLines["startLines"]:
docLine = f.readline()
if docLine.rstrip("\n") != startLine:
print("startLines is different, insert all.")
self.docObj.InsertChars(0, str(self))
return True
charCount += len(docLine)
# check titleLines
if self.withTitleLine:
for titleLine in self.actualLines["titleLines"]:
docLine = f.readline()
if docLine.rstrip("\n") != titleLine:
print("titleLines is different, insert all.")
self.docObj.InsertChars(0, str(self))
return True
charCount += len(docLine)
# get bodyLines char count
for bodyLine in self.actualLines["bodyLines"]:
docLine = f.readline()
charCount += len(docLine)
# check endLines
if self.withStartLine:
for endLine in self.actualLines["endLines"]:
docLine = f.readline()
if docLine.rstrip("\n") != endLine:
print("endLines is different, insert all.")
self.docObj.InsertChars(0, str(self))
return True
charCount += len(docLine)
# find postLine
for postLine in self.actualLines["postLines"]:
docLine = f.readline()
if docLine != postLine:
print("postLine is different, insert all.")
self.docObj.InsertChars(0, str(self))
return True
charCount += len(docLine)
# find last space line
spaceLines = ""
for i in range(self.lastSpaceLineCount):
docLine = f.readline()
if docLine != "\n":
spaceLines += "\n"
if spaceLines:
print("insert spaceLine under the postLine.")
self.docObj.InsertChars(charCount, spaceLines)
return True
self.docObj.DeleteChars(0, charCount - 1 + self.lastSpaceLineCount)
self.docObj.InsertChars(0, str(self))
def addLine(self, label, line):
if label in self.lines:
self.lines[label].append(line)
def updateHeader(self):
createTime = ""
modifyTime = datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")
if platform.system() in ["Linux", "Darwin"]:
p = subprocess.run(["stat", "-c", "%W", self.docObj.GetFilename()], capture_output=True, text=True)
createTime = datetime.datetime.fromtimestamp(int(p.stdout)).strftime("%Y/%m/%d %H:%M:%S")
elif platform.system() in ["Windows"]:
createTime = datetime.datetime.fromtimestamp(Path(self.docObj.GetFilename()).st_ctime).strftime("%Y/%m/%d %H:%M:%S")
self.actualLines = copy.deepcopy(self.lines)
# comment character
if self.commentChar and isinstance(self.commentChar, str):
self.commentChar = self.commentChar[0]
else:
print("commentChar error.")
return 0
# around character
if self.aroundChar and isinstance(self.aroundChar, str):
self.aroundChar = self.aroundChar[0]
# bodyLines
if self.withFullName:
self.bodyLines.append([self.commentChar, self.fileNameLabel, '', self.fullFileName, self.commentChar])
else:
self.bodyLines.append([self.commentChar, self.fileNameLabel, '', self.fileName, self.commentChar])
self.bodyLines.append([self.commentChar, self.createTimeLabel, '', createTime, self.commentChar])
self.bodyLines.append([self.commentChar, self.authorLabel, '', self.author, self.commentChar])
self.bodyLines.append([self.commentChar, self.emailLabel, '', self.email, self.commentChar])
self.bodyLines.append([self.commentChar, self.modifyDataLabel, '', modifyTime, self.commentChar])
self.bodyLines.append([self.commentChar, self.modifyByLabel, '', self.modifyBy, self.commentChar])
self.bodyLineMax = max([len(self.aroundChar.join(line)) for line in self.bodyLines])
if self.maxChar < self.bodyLineMax:
self.maxChar = self.bodyLineMax
# startLine
if self.withStartLine:
self.actualLines["startLines"].append(self.commentChar * self.maxChar)
# titleLine
if self.withTitleLine and self.title:
self.actualLines["titleLines"].append((self.aroundChar + self.title + self.aroundChar).center(self.maxChar, self.commentChar))
self.actualLines["titleLines"].append(self.commentChar * self.maxChar)
# bodylines
for line in self.bodyLines:
line.insert(3, self.filler * (self.maxChar - len(self.aroundChar.join(line)) - 1))
self.actualLines["bodyLines"].append(self.aroundChar.join(line))
# copyright
step = self.maxChar - 2 * len(self.commentChar) - 2 * len(self.aroundChar)
tmpLines = []
for i in range(0, len(self.copyRightLine), step):
tmpLines.append([self.commentChar, self.copyRightLine[i:i + step].ljust(step, self.filler), self.commentChar])
for line in tmpLines:
line[1] += self.filler * (step - len(line[1]))
self.actualLines["bodyLines"].append(self.aroundChar.join(line))
# endline
if self.withStartLine:
self.actualLines["endLines"].append(self.commentChar * self.maxChar)
def __str__(self):
result = ""
for key in self.actualLines:
if self.actualLines[key]:
result += "\n".join(self.actualLines[key]) + "\n"
result += "\n" * self.lastSpaceLineCount
return result
def __repr__(self):
return self.__str__
def _activetor_ah(plugin_id):
_plugin_id[0] = plugin_id
return True
_plugin = ["AutoHeaderPlugin", _activetor_ah]
def _connect(doc):
if Path(doc.GetFilename()).suffix in _fileType:
doc.Connect('presave', autoheader)
def autoheader(*args, **kwargs):
h = header(app.GetActiveDocument())
if h.docObj and Path(h.docObj.GetFilename()).suffix in _fileType:
h.fullFileName = h.docObj.GetFilename()
h.fileName = Path(h.docObj.GetFilename()).name
h.title = "yang's header"
h.author = "xxxx"
h.modifyBy = "xxxXx"
h.email = "xxxx@hotmail.com"
h.addLine("preLines", "#!/usr/bin/env python3")
h.addLine("preLines", "# -*- coding:utf-8 -*-")
h.copyRightLine = "Copyright (c) 2025 xxxx Culture Media Co., Ltd"
# print('update header for {}'.format(h.fileName))
h.docObj.BeginUndoAction()
try:
h.setheader()
finally:
h.docObj.EndUndoAction()
autoheader.label = "Auto Header"
autoheader.contexts = [wingapi.kContextNewMenu("Scripts"),
wingapi.kContextEditor(),
]
app.Connect("document-open", _connect)
# def _enablePlugin(editor):
# fn = Path(editor.GetDocument().GetFilename())
# if fn.suffix == '.py':
# app.EnablePlugin(_plugin_id[0], True)
# _preSaveId[0] = app.GetActiveDocument().Connect("presave", autoheader)
# else:
# app.EnablePlugin(_plugin_id[0], False)
# app.GetActiveDocument().Disconnect(_preSaveId[0])
# app.Connect("active-editor-changed", _enablePlugin)
