Skip to content

Commit

Permalink
add python scripts to update template; fix bugs
Browse files Browse the repository at this point in the history
1. Ported over (from kbilsted's old template)
    the ToolsForMaintainersOfTheProjectTemplate folder
    for updating some of the PluginInfrastructure
    files to stay up to date with Notepad++.
2. Fix bug where running tests multiple times in a single
    Notepad++ session causes the user interface tests to fail.
  • Loading branch information
molsonkiko committed Jan 15, 2024
1 parent 5a47ef5 commit 048a020
Show file tree
Hide file tree
Showing 11 changed files with 799 additions and 7 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [0.0.2] - (UNRELEASED) YYYY-MM-DD

### Added

1. Ported over (from kbilsted's old template) the [ToolsForMaintainersOfTheProjectTemplate](/ToolsForMaintainersOfTheProjectTemplate/) folder for updating some of the [PluginInfrastructure](/NppCSharpPluginPack/PluginInfrastructure/) files to stay up to date with Notepad++.

### Changed

1. Remove references and links to JsonTools (they now go to this project's GitHub repo).
Expand All @@ -29,6 +33,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

1. [TestRunner.cs](/NppCSharpPluginPack/Tests/TestRunner.cs) now restores clipboard text after tests.
2. Link label text and background now correctly switches back to defaults when going from a dark theme to default styles.
3. Fix bug where running tests multiple times in a single Notepad++ session causes the user interface tests to fail.

## [0.0.1] - 2024-01-13

Expand Down
8 changes: 7 additions & 1 deletion NppCSharpPluginPack/PluginInfrastructure/Msgs_h.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,13 @@ public enum LangType
L_ASM, L_DIFF, L_PROPS, L_PS, L_RUBY, L_SMALLTALK, L_VHDL, L_KIX, L_AU3,
L_CAML, L_ADA, L_VERILOG, L_MATLAB, L_HASKELL, L_INNO, L_SEARCHRESULT,
L_CMAKE, L_YAML, L_COBOL, L_GUI4CLI, L_D, L_POWERSHELL, L_R, L_JSP,
L_COFFEESCRIPT, L_JSON, L_JAVASCRIPT, L_FORTRAN_77,
L_COFFEESCRIPT, L_JSON, L_JAVASCRIPT, L_FORTRAN_77, L_BAANC, L_SREC,
L_IHEX, L_TEHEX, L_SWIFT,
L_ASN1, L_AVS, L_BLITZBASIC, L_PUREBASIC, L_FREEBASIC,
L_CSOUND, L_ERLANG, L_ESCRIPT, L_FORTH, L_LATEX,
L_MMIXAL, L_NIM, L_NNCRONTAB, L_OSCRIPT, L_REBOL,
L_REGISTRY, L_RUST, L_SPICE, L_TXT2TAGS, L_VISUALPROLOG,
L_TYPESCRIPT, L_JSON5, L_MSSQL, L_GDSCRIPT, L_HOLLYWOOD,
// Don't use L_JS, use L_JAVASCRIPT instead
// The end of enumated language type, so it should be always at the end
L_EXTERNAL
Expand Down
4 changes: 2 additions & 2 deletions NppCSharpPluginPack/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@
// Build Number
// Revision
//
[assembly: AssemblyVersion("0.0.1.2")]
[assembly: AssemblyFileVersion("0.0.1.2")]
[assembly: AssemblyVersion("0.0.1.3")]
[assembly: AssemblyFileVersion("0.0.1.3")]
3 changes: 2 additions & 1 deletion NppCSharpPluginPack/Tests/UserInterfaceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,8 @@ public static bool ExecuteFileManipulation(FileManipulation command, List<string
messages.Add("compare_clipboard passed");
break;
case FileManipulation.OpenSelectionRememberingForm:
Main.OpenSelectionRememberingForm();
if (Main.selectionRememberingForm == null || Main.selectionRememberingForm.IsDisposed || !Main.selectionRememberingForm.Visible)
Main.OpenSelectionRememberingForm();
messages.Add("open selection remembering form");
break;
case FileManipulation.SelectWithSelectionRememberingForm:
Expand Down
7 changes: 7 additions & 0 deletions PluginPackArchitecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ This is a fork of UFO's plugin package updated for VS2015, 2017, 2019, and 2022
* Select the new files, Right-click and choose "include in project"


## Keeping PluginInfrastructure up to date with Notepad++

Many of the files in the [PluginInfrastructure folder](/NppCSharpPluginPack/PluginInfrastructure/) were partially auto-generated from the Notepad++ source code, because it would be too much work to port all the code from C++ into C# by hand.

The way to regenerate the auto-generated portions of these code is to download the Notepad++ source code from master and run the Python scripts in [ToolsForMaintainersOfTheProjectTemplate](/ToolsForMaintainersOfTheProjectTemplate/) folder. Read the documentation of those scripts if you're still unsure how to proceed.


## Plugins using this pluginpack (or the original)

* https://github.com/kbilsted/NppPluginGuidHelper
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Face.py - module for reading and parsing Scintilla.iface file
# Implemented 2000 by Neil Hodgson neilh@scintilla.org
# Released to the public domain.
# Requires Python 2.5 or later

def sanitiseLine(line):
if line[-1:] == '\n': line = line[:-1]
pos = line.find("##")
if pos != -1:
line = line[:pos]
line = line.strip()
return line

def decodeFunction(featureVal):
retType, rest = featureVal.split(" ", 1)
nameIdent, params = rest.split("(")
name, value = nameIdent.split("=")
params, rest = params.split(")")
param1, param2 = params.split(",")
return retType, name, value, param1, param2

def decodeEvent(featureVal):
retType, rest = featureVal.split(" ", 1)
nameIdent, params = rest.split("(")
name, value = nameIdent.split("=")
return retType, name, value

def decodeParam(p):
param = p.strip()
type = ""
name = ""
value = ""
if " " in param:
type, nv = param.split(" ")
if "=" in nv:
name, value = nv.split("=")
else:
name = nv
return type, name, value

class Face:

def __init__(self):
self.order = []
self.features = {}
self.values = {}
self.events = {}

def ReadFromFile(self, name):
currentCategory = ""
currentComment = []
currentCommentFinished = 0
file = open(name)
for line in file.readlines():
line = sanitiseLine(line)
if line:
if line[0] == "#":
if line[1] == " ":
if currentCommentFinished:
currentComment = []
currentCommentFinished = 0
currentComment.append(line[2:])
else:
currentCommentFinished = 1
featureType, featureVal = line.split(" ", 1)
if featureType in ["fun", "get", "set"]:
try:
retType, name, value, param1, param2 = decodeFunction(featureVal)
except ValueError:
print("Failed to decode %s" % line)
raise
p1 = decodeParam(param1)
p2 = decodeParam(param2)
self.features[name] = {
"FeatureType": featureType,
"ReturnType": retType,
"Value": value,
"Param1Type": p1[0], "Param1Name": p1[1], "Param1Value": p1[2],
"Param2Type": p2[0], "Param2Name": p2[1], "Param2Value": p2[2],
"Category": currentCategory, "Comment": currentComment
}
if value in self.values:
raise Exception("Duplicate value " + value + " " + name)
self.values[value] = 1
self.order.append(name)
elif featureType == "evt":
retType, name, value = decodeEvent(featureVal)
self.features[name] = {
"FeatureType": featureType,
"ReturnType": retType,
"Value": value,
"Category": currentCategory, "Comment": currentComment
}
if value in self.events:
raise Exception("Duplicate event " + value + " " + name)
self.events[value] = 1
self.order.append(name)
elif featureType == "cat":
currentCategory = featureVal
elif featureType == "val":
try:
name, value = featureVal.split("=", 1)
except ValueError:
print("Failure %s" % featureVal)
raise Exception()
self.features[name] = {
"FeatureType": featureType,
"Category": currentCategory,
"Value": value }
self.order.append(name)
elif featureType == "enu" or featureType == "lex":
name, value = featureVal.split("=", 1)
self.features[name] = {
"FeatureType": featureType,
"Category": currentCategory,
"Value": value,
"Comment": currentComment
}
self.order.append(name)

Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
#!/usr/bin/env python
# FileGenerator.py - implemented 2013 by Neil Hodgson neilh@scintilla.org
# Released to the public domain.

# Generate or regenerate source files based on comments in those files.
# May be modified in-place or a template may be generated into a complete file.
# Requires Python 2.5 or later
# The files are copied to a string apart from sections between a
# ++Autogenerated comment and a --Autogenerated comment which is
# generated by the CopyWithInsertion function. After the whole string is
# instantiated, it is compared with the target file and if different the file
# is rewritten.

from __future__ import with_statement

import codecs, os, re, string, sys

lineEnd = "\r\n" if sys.platform == "win32" else "\n"

def UpdateFile(filename, updated):
""" If the file contents are different to updated then copy updated into the
file else leave alone so Mercurial and make don't treat it as modified. """
newOrChanged = "Changed"
try:
with codecs.open(filename, "r", "utf-8") as infile:
original = infile.read()
if updated == original:
print("Nothing new to update:", os.path.basename(filename))
# Same as before so don't write
return
os.unlink(filename)
except IOError: # File is not there yet
newOrChanged = "New"
with codecs.open(filename, "w", "utf-8") as outfile:
outfile.write(updated)
print("%s %s" % (newOrChanged, filename))

# Automatically generated sections contain start and end comments,
# a definition line and the results.
# The results are replaced by regenerating based on the definition line.
# The definition line is a comment prefix followed by "**".
# If there is a digit after the ** then this indicates which list to use
# and the digit and next character are not part of the definition
# Backslash is used as an escape within the definition line.
# The part between \( and \) is repeated for each item in the list.
# \* is replaced by each list item. \t, and \n are tab and newline.
# If there is no definition line than the first list is copied verbatim.
# If retainDefs then the comments controlling generation are copied.
def CopyWithInsertion(input, commentPrefix, retainDefs, lists):
copying = 1
generated = False
listid = 0
output = []
for line in input.splitlines(0):
isStartGenerated = line.lstrip().startswith(commentPrefix + "++Autogenerated")
if copying and not isStartGenerated:
output.append(line)
if isStartGenerated:
if retainDefs:
output.append(line)
copying = 0
generated = False
elif not copying and not generated:
# Generating
if line.startswith(commentPrefix + "**"):
# Pattern to transform input data
if retainDefs:
output.append(line)
definition = line[len(commentPrefix + "**"):]
if (commentPrefix == "<!--") and (" -->" in definition):
definition = definition.replace(" -->", "")
listid = 0
if definition[0] in string.digits:
listid = int(definition[:1])
definition = definition[2:]
# Hide double slashes as a control character
definition = definition.replace("\\\\", "\001")
# Do some normal C style transforms
definition = definition.replace("\\n", "\n")
definition = definition.replace("\\t", "\t")
# Get the doubled backslashes back as single backslashes
definition = definition.replace("\001", "\\")
startRepeat = definition.find("\\(")
endRepeat = definition.find("\\)")
intro = definition[:startRepeat]
out = ""
if intro.endswith("\n"):
pos = 0
else:
pos = len(intro)
out += intro
middle = definition[startRepeat+2:endRepeat]
for i in lists[listid]:
item = middle.replace("\\*", i)
if pos and (pos + len(item) >= 80):
out += "\\\n"
pos = 0
out += item
pos += len(item)
if item.endswith("\n"):
pos = 0
outro = definition[endRepeat+2:]
out += outro
out = out.replace("\n", lineEnd) # correct EOLs in generated content
output.append(out)
else:
# Simple form with no rule to transform input
output.extend(lists[0])
generated = True
if line.lstrip().startswith(commentPrefix + "--Autogenerated") or \
line.lstrip().startswith(commentPrefix + "~~Autogenerated"):
copying = 1
if retainDefs:
output.append(line)
output = [line.rstrip(" \t") for line in output] # trim trailing whitespace
return lineEnd.join(output) + lineEnd

def GenerateFile(inpath, outpath, commentPrefix, retainDefs, *lists):
"""Generate 'outpath' from 'inpath'.
"""

try:
with codecs.open(inpath, "r", "UTF-8") as infile:
original = infile.read()
updated = CopyWithInsertion(original, commentPrefix,
retainDefs, lists)
UpdateFile(outpath, updated)
except IOError:
print("Can not open %s" % inpath)

def Generate(inpath, outpath, commentPrefix, *lists):
"""Generate 'outpath' from 'inpath'.
"""
GenerateFile(inpath, outpath, commentPrefix, inpath == outpath, *lists)

def Regenerate(filename, commentPrefix, *lists):
"""Regenerate the given file.
"""
Generate(filename, filename, commentPrefix, *lists)

def UpdateLineInFile(path, linePrefix, lineReplace):
lines = []
updated = False
with codecs.open(path, "r", "utf-8") as f:
for l in f.readlines():
l = l.rstrip()
if not updated and l.startswith(linePrefix):
lines.append(lineReplace)
updated = True
else:
lines.append(l)
contents = lineEnd.join(lines) + lineEnd
UpdateFile(path, contents)

def ReplaceREInFile(path, match, replace):
with codecs.open(path, "r", "utf-8") as f:
contents = f.read()
contents = re.sub(match, replace, contents)
UpdateFile(path, contents)
Loading

0 comments on commit 048a020

Please sign in to comment.