You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
213 lines
6.5 KiB
213 lines
6.5 KiB
# -*- coding: utf-8 -*- |
|
|
|
from __future__ import unicode_literals |
|
|
|
import ctypes |
|
|
|
from ctypes import c_int, c_char_p, c_long, c_ssize_t |
|
|
|
def IsEnumeration(t): |
|
return t[:1].isupper() |
|
|
|
basicTypes = ["bool", "int", "position", "line", "pointer", "colour", "colouralpha"] |
|
|
|
def BasicTypeOrEnumeration(t): |
|
return t in basicTypes or IsEnumeration(t) |
|
|
|
class TEXTRANGE(ctypes.Structure): |
|
_fields_= (\ |
|
('cpMin', c_long), |
|
('cpMax', c_long), |
|
('lpstrText', ctypes.POINTER(ctypes.c_char)), |
|
) |
|
|
|
class TEXTRANGEFULL(ctypes.Structure): |
|
_fields_= (\ |
|
('cpMin', c_ssize_t), |
|
('cpMax', c_ssize_t), |
|
('lpstrText', ctypes.POINTER(ctypes.c_char)), |
|
) |
|
|
|
class FINDTEXT(ctypes.Structure): |
|
_fields_= (\ |
|
('cpMin', c_long), |
|
('cpMax', c_long), |
|
('lpstrText', c_char_p), |
|
('cpMinText', c_long), |
|
('cpMaxText', c_long), |
|
) |
|
|
|
class FINDTEXTFULL(ctypes.Structure): |
|
_fields_= (\ |
|
('cpMin', c_ssize_t), |
|
('cpMax', c_ssize_t), |
|
('lpstrText', c_char_p), |
|
('cpMinText', c_ssize_t), |
|
('cpMaxText', c_ssize_t), |
|
) |
|
|
|
class SciCall: |
|
def __init__(self, fn, ptr, msg, stringResult=False): |
|
self._fn = fn |
|
self._ptr = ptr |
|
self._msg = msg |
|
self._stringResult = stringResult |
|
def __call__(self, w=0, lp=0): |
|
ww = ctypes.cast(w, c_char_p) |
|
if self._stringResult: |
|
lengthBytes = self._fn(self._ptr, self._msg, ww, None) |
|
if lengthBytes == 0: |
|
return bytearray() |
|
result = (ctypes.c_byte * lengthBytes)(0) |
|
lengthBytes2 = self._fn(self._ptr, self._msg, ww, ctypes.cast(result, c_char_p)) |
|
assert lengthBytes == lengthBytes2 |
|
return bytearray(result)[:lengthBytes] |
|
else: |
|
ll = ctypes.cast(lp, c_char_p) |
|
return self._fn(self._ptr, self._msg, ww, ll) |
|
|
|
sciFX = ctypes.CFUNCTYPE(c_ssize_t, c_char_p, c_int, c_char_p, c_char_p) |
|
|
|
class ScintillaCallable: |
|
def __init__(self, face, scifn, sciptr): |
|
self.__dict__["face"] = face |
|
self.__dict__["used"] = set() |
|
self.__dict__["all"] = set() |
|
# The k member is for accessing constants as a dictionary |
|
self.__dict__["k"] = {} |
|
for f in face.features: |
|
self.all.add(f) |
|
if face.features[f]["FeatureType"] == "val": |
|
self.k[f] = int(self.face.features[f]["Value"], 0) |
|
elif face.features[f]["FeatureType"] == "evt": |
|
self.k["SCN_"+f] = int(self.face.features[f]["Value"], 0) |
|
scifn = sciFX(scifn) |
|
self.__dict__["_scifn"] = scifn |
|
self.__dict__["_sciptr"] = sciptr |
|
def __getattr__(self, name): |
|
if name in self.face.features: |
|
self.used.add(name) |
|
feature = self.face.features[name] |
|
value = int(feature["Value"], 0) |
|
#~ print("Feature", name, feature) |
|
if feature["FeatureType"] == "val": |
|
self.__dict__[name] = value |
|
return value |
|
else: |
|
if feature["Param2Type"] == "stringresult" and \ |
|
name not in ["GetText", "GetLine", "GetCurLine"]: |
|
return SciCall(self._scifn, self._sciptr, value, True) |
|
else: |
|
return SciCall(self._scifn, self._sciptr, value) |
|
elif ("Get" + name) in self.face.features: |
|
self.used.add("Get" + name) |
|
feature = self.face.features["Get" + name] |
|
value = int(feature["Value"], 0) |
|
if feature["FeatureType"] == "get" and \ |
|
not name.startswith("Get") and \ |
|
not feature["Param1Type"] and \ |
|
not feature["Param2Type"] and \ |
|
BasicTypeOrEnumeration(feature["ReturnType"]): |
|
#~ print("property", feature) |
|
return self._scifn(self._sciptr, value, None, None) |
|
elif name.startswith("SCN_") and name in self.k: |
|
self.used.add(name) |
|
feature = self.face.features[name[4:]] |
|
value = int(feature["Value"], 0) |
|
#~ print("Feature", name, feature) |
|
if feature["FeatureType"] == "val": |
|
return value |
|
raise AttributeError(name) |
|
def __setattr__(self, name, val): |
|
if ("Set" + name) in self.face.features: |
|
self.used.add("Set" + name) |
|
feature = self.face.features["Set" + name] |
|
value = int(feature["Value"], 0) |
|
#~ print("setproperty", feature) |
|
if feature["FeatureType"] == "set" and not name.startswith("Set"): |
|
if BasicTypeOrEnumeration(feature["Param1Type"]): |
|
return self._scifn(self._sciptr, value, c_char_p(val), None) |
|
elif feature["Param2Type"] in ["string"]: |
|
return self._scifn(self._sciptr, value, None, c_char_p(val)) |
|
raise AttributeError(name) |
|
raise AttributeError(name) |
|
def getvalue(self, name): |
|
if name in self.face.features: |
|
feature = self.face.features[name] |
|
if feature["FeatureType"] != "evt": |
|
try: |
|
return int(feature["Value"], 0) |
|
except ValueError: |
|
return -1 |
|
return -1 |
|
|
|
|
|
def ByteRange(self, start, end): |
|
tr = TEXTRANGE() |
|
tr.cpMin = start |
|
tr.cpMax = end |
|
length = end - start |
|
tr.lpstrText = ctypes.create_string_buffer(length + 1) |
|
self.GetTextRange(0, ctypes.byref(tr)) |
|
text = tr.lpstrText[:length] |
|
text += b"\0" * (length - len(text)) |
|
return text |
|
def ByteRangeFull(self, start, end): |
|
tr = TEXTRANGEFULL() |
|
tr.cpMin = start |
|
tr.cpMax = end |
|
length = end - start |
|
tr.lpstrText = ctypes.create_string_buffer(length + 1) |
|
self.GetTextRangeFull(0, ctypes.byref(tr)) |
|
text = tr.lpstrText[:length] |
|
text += b"\0" * (length - len(text)) |
|
return text |
|
def StyledTextRange(self, start, end): |
|
tr = TEXTRANGE() |
|
tr.cpMin = start |
|
tr.cpMax = end |
|
length = 2 * (end - start) |
|
tr.lpstrText = ctypes.create_string_buffer(length + 2) |
|
self.GetStyledText(0, ctypes.byref(tr)) |
|
styledText = tr.lpstrText[:length] |
|
styledText += b"\0" * (length - len(styledText)) |
|
return styledText |
|
def StyledTextRangeFull(self, start, end): |
|
tr = TEXTRANGEFULL() |
|
tr.cpMin = start |
|
tr.cpMax = end |
|
length = 2 * (end - start) |
|
tr.lpstrText = ctypes.create_string_buffer(length + 2) |
|
self.GetStyledTextFull(0, ctypes.byref(tr)) |
|
styledText = tr.lpstrText[:length] |
|
styledText += b"\0" * (length - len(styledText)) |
|
return styledText |
|
def FindBytes(self, start, end, s, flags): |
|
ft = FINDTEXT() |
|
ft.cpMin = start |
|
ft.cpMax = end |
|
ft.lpstrText = s |
|
ft.cpMinText = 0 |
|
ft.cpMaxText = 0 |
|
pos = self.FindText(flags, ctypes.byref(ft)) |
|
#~ print(start, end, ft.cpMinText, ft.cpMaxText) |
|
return pos |
|
def FindBytesFull(self, start, end, s, flags): |
|
ft = FINDTEXTFULL() |
|
ft.cpMin = start |
|
ft.cpMax = end |
|
ft.lpstrText = s |
|
ft.cpMinText = 0 |
|
ft.cpMaxText = 0 |
|
pos = self.FindTextFull(flags, ctypes.byref(ft)) |
|
#~ print(start, end, ft.cpMinText, ft.cpMaxText) |
|
return pos |
|
|
|
def Contents(self): |
|
return self.ByteRange(0, self.Length) |
|
|
|
def SetContents(self, s): |
|
self.TargetStart = 0 |
|
self.TargetEnd = self.Length |
|
self.ReplaceTarget(len(s), s) |
|
|
|
|