From 1b153f8d8d4b2f09afc2d039256c958e94bd3b05 Mon Sep 17 00:00:00 2001 From: Neil Date: Wed, 20 Dec 2023 09:24:23 +1100 Subject: Add IDocumentEditable interface for efficient interaction with document objects. --- call/ScintillaCall.cxx | 14 ++++----- doc/ScintillaDoc.html | 67 ++++++++++++++++++++++++++++++++++++-------- doc/ScintillaHistory.html | 7 +++++ include/ILoader.h | 13 +++++++++ include/ScintillaCall.h | 12 ++++---- scripts/ScintillaAPIFacer.py | 18 +++++++----- src/Document.cxx | 12 ++++++-- src/Document.h | 6 ++-- src/Editor.cxx | 14 +++++---- 9 files changed, 124 insertions(+), 39 deletions(-) diff --git a/call/ScintillaCall.cxx b/call/ScintillaCall.cxx index 99e400e28..98e1dbd3e 100644 --- a/call/ScintillaCall.cxx +++ b/call/ScintillaCall.cxx @@ -2071,11 +2071,11 @@ void ScintillaCall::SetViewEOL(bool visible) { Call(Message::SetViewEOL, visible); } -void *ScintillaCall::DocPointer() { - return reinterpret_cast(Call(Message::GetDocPointer)); +IDocumentEditable *ScintillaCall::DocPointer() { + return reinterpret_cast(Call(Message::GetDocPointer)); } -void ScintillaCall::SetDocPointer(void *doc) { +void ScintillaCall::SetDocPointer(IDocumentEditable *doc) { CallPointer(Message::SetDocPointer, 0, doc); } @@ -2151,15 +2151,15 @@ int ScintillaCall::Zoom() { return static_cast(Call(Message::GetZoom)); } -void *ScintillaCall::CreateDocument(Position bytes, Scintilla::DocumentOption documentOptions) { - return reinterpret_cast(Call(Message::CreateDocument, bytes, static_cast(documentOptions))); +IDocumentEditable *ScintillaCall::CreateDocument(Position bytes, Scintilla::DocumentOption documentOptions) { + return reinterpret_cast(Call(Message::CreateDocument, bytes, static_cast(documentOptions))); } -void ScintillaCall::AddRefDocument(void *doc) { +void ScintillaCall::AddRefDocument(IDocumentEditable *doc) { CallPointer(Message::AddRefDocument, 0, doc); } -void ScintillaCall::ReleaseDocument(void *doc) { +void ScintillaCall::ReleaseDocument(IDocumentEditable *doc) { CallPointer(Message::ReleaseDocument, 0, doc); } diff --git a/doc/ScintillaDoc.html b/doc/ScintillaDoc.html index 27a542e90..3035d2210 100644 --- a/doc/ScintillaDoc.html +++ b/doc/ScintillaDoc.html @@ -129,7 +129,7 @@

Scintilla Documentation

-

Last edited 5 November 2023 NH

+

Last edited 19 December 2023 NH

Scintilla 5 has moved the lexers from Scintilla into a new Lexilla project.
@@ -402,34 +402,35 @@ ○ Multiple viewsBackground loading and saving - ○ Folding + ○ Document interface + ○ FoldingLine wrappingZooming - ○ Long lines + ○ Long linesAccessibilityLexer - ○ Lexer objects + ○ Lexer objectsNotificationsImages - ○ GTK + ○ GTKProvisional messagesDeprecated messages - ○ Edit messages never supported by Scintilla + ○ Edit messages never supported by ScintillaRemoved featuresBuilding Scintilla @@ -7203,9 +7204,11 @@ sptr_t CallScintilla(unsigned int iMessage, uptr_t wParam, sptr_t lParam){ windows (for use with splitter windows).

These messages use pointer returns and arguments to refer to documents. - They point to internal objects inside Scintilla and should be treated as an opaque void*. That - is, you can use and store the pointer as described in this section but you should not - dereference it.

+ They point to IDocumentEditable objects inside + Scintilla. + The IDocumentEditable interface is provisional and may change. + Client code can call IDocumentEditable methods. + Clients may just treat these as opaque void* values that are received from and passed to Scintilla without dereferencing.

SCI_GETDOCPOINTER → pointer
SCI_SETDOCPOINTER(<unused>, pointer doc)
SCI_CREATEDOCUMENT(position bytes, int documentOptions) → pointer
@@ -7339,7 +7342,7 @@ sptr_t CallScintilla(unsigned int iMessage, uptr_t wParam, sptr_t lParam){

The documentOptions argument is described in the SCI_CREATEDOCUMENT section.

-

ILoader

+

ILoader

class ILoader {
@@ -7356,7 +7359,9 @@ sptr_t CallScintilla(unsigned int iMessage, uptr_t wParam, sptr_t lParam){ If a failure occurs in AddData or in a file reading call then loading can be abandoned and the loader released with the Release call. When the whole file has been read, ConvertToDocument should be called to produce a Scintilla - document pointer. The newly created document will have a reference count of 1 in the same way as a document pointer + document pointer. This pointer can be treated as a void* cookie to pass to other APIs or cast to a + IDocumentEditable* pointer. + The newly created document will have a reference count of 1 in the same way as a document pointer returned from SCI_CREATEDOCUMENT. There is no need to call Release after ConvertToDocument.

@@ -7373,6 +7378,46 @@ sptr_t CallScintilla(unsigned int iMessage, uptr_t wParam, sptr_t lParam){ The application may then decide to ignore the modification or to terminate the background saving thread and reenable modification before returning from the notification.

+

Document interface

+ +

Applications may want to manipulate documents that are not visible and the provisional IDocumentEditable + interface can be used for this.

+ +

IDocumentEditable allows more direct access to functionality and is faster than calling Scintilla APIs.

+ +

IDocumentEditable pointers are returned by + SCI_CREATEDOCUMENT, + SCI_GETDOCPOINTER, and + ILoader::ConvertToDocument.

+ +

They may be passed to + SCI_ADDREFDOCUMENT, + SCI_RELEASEDOCUMENT, and + SCI_SETDOCPOINTER, + .

+ +

IDocumentEditable

+ +
+class IDocumentEditable {
+public:
+        // Allow this interface to add methods over time and discover whether new methods available.
+        virtual int SCI_METHOD DEVersion() const noexcept = 0;
+
+        // Lifetime control
+        virtual int SCI_METHOD AddRef() noexcept = 0;
+        virtual int SCI_METHOD Release() = 0;
+};
+
+
+ +

The IDocumentEditable interface is being developed and more methods will be added in the future. + Its also possible that methods will change signatures or be removed. + Thus the feature is provisional and users should be aware that they may have to modify client code in response to these changes.

+ +

DEVersion will return 0 while IDocumentEditable is provisional and will return 1 + for the first stable release. After that, it will be incremented when new methods are added.

+

Folding

The fundamental operation in folding is making lines invisible or visible. Line visibility diff --git a/doc/ScintillaHistory.html b/doc/ScintillaHistory.html index 00023b102..a3d44d4ae 100644 --- a/doc/ScintillaHistory.html +++ b/doc/ScintillaHistory.html @@ -591,6 +591,13 @@ Released 18 November 2023.

  • + Add IDocumentEditable interface to allow efficient interaction with document objects which may not be visible in + a Scintilla instance. This feature is provisonal and may change before being declared stable. + For better type-safety, the ScintillaCall C++ API uses IDocumentEditable* where void* was used before which may require + changes to client code that uses document pointer APIs + DocPointer, SetDocPointer, CreateDocument, AddRefDocument, and ReleaseDocument. +
  • +
  • Ctrl-click on a selection deselects it in multiple selection mode.
  • diff --git a/include/ILoader.h b/include/ILoader.h index 2fa69f527..5d2eb2571 100644 --- a/include/ILoader.h +++ b/include/ILoader.h @@ -1,6 +1,7 @@ // Scintilla source code edit control /** @file ILoader.h ** Interface for loading into a Scintilla document from a background thread. + ** Interface for manipulating a document without a view. **/ // Copyright 1998-2017 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. @@ -20,6 +21,18 @@ public: virtual void * SCI_METHOD ConvertToDocument() = 0; }; +static constexpr int deRelease0 = 0; + +class IDocumentEditable { +public: + // Allow this interface to add methods over time and discover whether new methods available. + virtual int SCI_METHOD DEVersion() const noexcept = 0; + + // Lifetime control + virtual int SCI_METHOD AddRef() noexcept = 0; + virtual int SCI_METHOD Release() = 0; +}; + } #endif diff --git a/include/ScintillaCall.h b/include/ScintillaCall.h index 1a1a1e0f2..0ce4366d7 100644 --- a/include/ScintillaCall.h +++ b/include/ScintillaCall.h @@ -20,6 +20,8 @@ struct TextRangeFull; struct TextToFindFull; struct RangeToFormatFull; +class IDocumentEditable; + using FunctionDirect = intptr_t(*)(intptr_t ptr, unsigned int iMessage, uintptr_t wParam, intptr_t lParam, int *pStatus); struct Failure { @@ -561,8 +563,8 @@ public: Position BraceMatchNext(Position pos, Position startPos); bool ViewEOL(); void SetViewEOL(bool visible); - void *DocPointer(); - void SetDocPointer(void *doc); + IDocumentEditable *DocPointer(); + void SetDocPointer(IDocumentEditable *doc); void SetModEventMask(Scintilla::ModificationFlags eventMask); Position EdgeColumn(); void SetEdgeColumn(Position column); @@ -581,9 +583,9 @@ public: bool SelectionIsRectangle(); void SetZoom(int zoomInPoints); int Zoom(); - void *CreateDocument(Position bytes, Scintilla::DocumentOption documentOptions); - void AddRefDocument(void *doc); - void ReleaseDocument(void *doc); + IDocumentEditable *CreateDocument(Position bytes, Scintilla::DocumentOption documentOptions); + void AddRefDocument(IDocumentEditable *doc); + void ReleaseDocument(IDocumentEditable *doc); Scintilla::DocumentOption DocumentOptions(); Scintilla::ModificationFlags ModEventMask(); void SetCommandEvents(bool commandEvents); diff --git a/scripts/ScintillaAPIFacer.py b/scripts/ScintillaAPIFacer.py index f26389abb..9caa1ea7f 100644 --- a/scripts/ScintillaAPIFacer.py +++ b/scripts/ScintillaAPIFacer.py @@ -55,7 +55,9 @@ deadValues = [ ] def ActualTypeName(type, identifier=None): - if type in typeAliases: + if type == "pointer" and identifier in ["doc", "DocPointer", "CreateDocument"]: + return "IDocumentEditable *" + elif type in typeAliases: return typeAliases[type] else: return type @@ -63,6 +65,8 @@ def ActualTypeName(type, identifier=None): def IsEnumeration(s): if s in ["Position", "Line", "Colour", "ColourAlpha"]: return False + if s.endswith("*"): + return False return s[:1].isupper() def JoinTypeAndIdentifier(type, identifier): @@ -219,7 +223,7 @@ def HMethods(f): if v["FeatureType"] in ["fun", "get", "set"]: if v["FeatureType"] == "get" and name.startswith("Get"): name = name[len("Get"):] - retType = ActualTypeName(v["ReturnType"]) + retType = ActualTypeName(v["ReturnType"], name) if IsEnumeration(retType): retType = namespace + retType parameters, args, callName = ParametersArgsCallname(v) @@ -241,21 +245,21 @@ def CXXMethods(f): msgName = "Message::" + name if v["FeatureType"] == "get" and name.startswith("Get"): name = name[len("Get"):] - retType = ActualTypeName(v["ReturnType"]) + retType = ActualTypeName(v["ReturnType"], name) parameters, args, callName = ParametersArgsCallname(v) returnIfNeeded = "return " if retType != "void" else "" out.append(JoinTypeAndIdentifier(retType, "ScintillaCall::" + name) + "(" + parameters + ")" + " {") retCast = "" retCastEnd = "" - if retType not in basicTypes or retType in ["int", "Colour", "ColourAlpha"]: + if retType.endswith("*"): + retCast = "reinterpret_cast<" + retType + ">(" + retCastEnd = ")" + elif retType not in basicTypes or retType in ["int", "Colour", "ColourAlpha"]: if IsEnumeration(retType): retType = namespace + retType retCast = "static_cast<" + retType + ">(" retCastEnd = ")" - elif retType in ["void *"]: - retCast = "reinterpret_cast<" + retType + ">(" - retCastEnd = ")" out.append("\t" + returnIfNeeded + retCast + callName + "(" + msgName + args + ")" + retCastEnd + ";") out.append("}") out.append("") diff --git a/src/Document.cxx b/src/Document.cxx index dcb087930..d67cac25e 100644 --- a/src/Document.cxx +++ b/src/Document.cxx @@ -184,7 +184,7 @@ Document::~Document() { } // Increase reference count and return its previous value. -int Document::AddRef() { +int SCI_METHOD Document::AddRef() noexcept { return refCount++; } @@ -461,6 +461,10 @@ Sci_Position SCI_METHOD Document::LineEnd(Sci_Position line) const { return cb.LineEnd(line); } +int SCI_METHOD Document::DEVersion() const noexcept { + return deRelease0; +} + void SCI_METHOD Document::SetErrorStatus(int status) { // Tell the watchers an error has occurred. for (const WatcherWithUserData &watcher : watchers) { @@ -1341,8 +1345,12 @@ int SCI_METHOD Document::AddData(const char *data, Sci_Position length) { return static_cast(Status::Ok); } +IDocumentEditable *Document::AsDocumentEditable() noexcept { + return static_cast(this); +} + void * SCI_METHOD Document::ConvertToDocument() { - return this; + return AsDocumentEditable(); } Sci::Position Document::Undo() { diff --git a/src/Document.h b/src/Document.h index f7f4eeedd..9f51fc719 100644 --- a/src/Document.h +++ b/src/Document.h @@ -259,7 +259,7 @@ struct CharacterExtracted { /** */ -class Document : PerLine, public Scintilla::IDocument, public Scintilla::ILoader { +class Document : PerLine, public Scintilla::IDocument, public Scintilla::ILoader, public Scintilla::IDocumentEditable { public: /** Used to pair watcher pointer with user data. */ @@ -329,7 +329,7 @@ public: Document &operator=(Document &&) = delete; ~Document() override; - int AddRef(); + int SCI_METHOD AddRef() noexcept override; int SCI_METHOD Release() override; // From PerLine @@ -347,6 +347,7 @@ public: int SCI_METHOD Version() const override { return Scintilla::dvRelease4; } + int SCI_METHOD DEVersion() const noexcept override; void SCI_METHOD SetErrorStatus(int status) override; @@ -383,6 +384,7 @@ public: Sci::Position InsertString(Sci::Position position, std::string_view sv); void ChangeInsertion(const char *s, Sci::Position length); int SCI_METHOD AddData(const char *data, Sci_Position length) override; + IDocumentEditable *AsDocumentEditable() noexcept; void * SCI_METHOD ConvertToDocument() override; Sci::Position Undo(); Sci::Position Redo(); diff --git a/src/Editor.cxx b/src/Editor.cxx index 28d680d7a..8f29d3a8f 100644 --- a/src/Editor.cxx +++ b/src/Editor.cxx @@ -6079,6 +6079,10 @@ constexpr Selection::SelTypes SelTypeFromMode(SelectionMode mode) { } } +sptr_t SPtrFromPtr(void *ptr) noexcept { + return reinterpret_cast(ptr); +} + } void Editor::SetSelectionMode(uptr_t wParam, bool setMoveExtends) { @@ -8216,11 +8220,11 @@ sptr_t Editor::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) { break; case Message::GetDocPointer: - return reinterpret_cast(pdoc); + return SPtrFromPtr(pdoc->AsDocumentEditable()); case Message::SetDocPointer: CancelModes(); - SetDocPointer(static_cast(PtrFromSPtr(lParam))); + SetDocPointer(static_cast(static_cast(PtrFromSPtr(lParam)))); return 0; case Message::CreateDocument: { @@ -8228,15 +8232,15 @@ sptr_t Editor::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) { doc->AddRef(); doc->Allocate(PositionFromUPtr(wParam)); pcs = ContractionStateCreate(pdoc->IsLarge()); - return reinterpret_cast(doc); + return SPtrFromPtr(doc->AsDocumentEditable()); } case Message::AddRefDocument: - (static_cast(PtrFromSPtr(lParam)))->AddRef(); + (static_cast(PtrFromSPtr(lParam)))->AddRef(); break; case Message::ReleaseDocument: - (static_cast(PtrFromSPtr(lParam)))->Release(); + (static_cast(PtrFromSPtr(lParam)))->Release(); break; case Message::GetDocumentOptions: -- cgit v1.2.3