载入中...
搜索中...
未找到
EditorSession.cpp
浏览该文件的文档.
2
7
8#include <algorithm>
9#include <exception>
10
11namespace eve::editor {
12
13EditorSession::EditorSession() : context_(this) {}
14
15IEditableTarget* EditorContext::target() const { return session_ ? session_->target() : nullptr; }
16
18
19bool EditorContext::execute(std::unique_ptr<IEditCommand> command) const {
20 return session_ && session_->execute(std::move(command));
21}
22
23Result<void> EditorContext::executeChecked(std::unique_ptr<IEditCommand> command) const {
24 if (!session_)
25 return eve::editing::failed<void>(EditorStatus::Failed, RuleId("editor.context.missing-session"),
26 "Editor context has no dispatching session");
27 return session_->executeChecked(std::move(command));
28}
29
30bool EditorSession::execute(std::unique_ptr<IEditCommand> command) {
31 return executeChecked(std::move(command)).ok();
32}
33
34Result<void> EditorSession::executeChecked(std::unique_ptr<IEditCommand> command) {
35 if (!command)
36 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.command.null"),
37 "Editor command must not be null");
38 Result<void> constrained = constraints_.evaluateChecked(context_, *command);
39 if (!constrained.ok()) return constrained;
40 auto appended = transactions_.append(std::move(command));
41 if (!appended.ok()) return appended;
42 return Result<void>::success(eve::Status(EditorStatus::Applied, constrained.diagnostics()));
43}
44
46 releaseTargetBinding();
47 target_ = &target;
48 boundTargetId_ = TargetId(target.targetId());
49 targetGeneration_ = nextDirectTargetGeneration_++;
50 targetLifetime_ = {};
51 targetLifetimeTracked_ = false;
52}
53
60
61void EditorSession::bindTrackedTarget(IEditableTarget& target, std::weak_ptr<void> lifetime,
62 EditorTargetCoordinator& coordinator, std::uint64_t generation) {
63 releaseTargetBinding();
64 target_ = &target;
65 boundTargetId_ = TargetId(target.targetId());
66 targetLifetime_ = std::move(lifetime);
67 targetLifetimeTracked_ = true;
68 targetGeneration_ = generation;
69 targetCoordinator_ = &coordinator;
70}
71
72void EditorSession::releaseTargetBinding() {
73 transactions_.clear();
75 if (targetCoordinator_) targetCoordinator_->detach(*this);
76 target_ = nullptr;
77 boundTargetId_ = {};
78 targetLifetime_ = {};
79 targetLifetimeTracked_ = false;
80 targetGeneration_ = 0;
81 targetCoordinator_ = nullptr;
82}
83
84void EditorSession::clearTarget() { releaseTargetBinding(); }
85
86void EditorSession::invalidateTrackedTarget(EditorTargetCoordinator& coordinator, const TargetId& target,
87 std::uint64_t generation) {
88 if (targetCoordinator_ != &coordinator || boundTargetId_ != target || targetGeneration_ != generation) return;
89 releaseTargetBinding();
90}
91
92void EditorSession::coordinatorDestroyed(EditorTargetCoordinator& coordinator) noexcept {
93 if (targetCoordinator_ != &coordinator) return;
94 try {
95 transactions_.clear();
96 } catch (...) {
97 }
98 clearRetainedPlans();
99 target_ = nullptr;
100 boundTargetId_ = {};
101 targetLifetime_ = {};
102 targetLifetimeTracked_ = false;
103 targetGeneration_ = 0;
104 targetCoordinator_ = nullptr;
105}
106
108 if (!target_) return nullptr;
109 if (targetLifetimeTracked_ && targetLifetime_.expired()) return nullptr;
110 return target_;
111}
112
115 if (!commandService_)
116 return eve::editing::failed<EditorValue>(EditorStatus::Failed, RuleId("editor.command.missing-service"),
117 "Editor session has no command service");
118
119 const CommandDescriptor* descriptor = commandService_->find(id);
120 const bool ownsTransaction = descriptor && descriptor->createsTransaction && !transactions_.isActive();
121 if (ownsTransaction) {
122 auto begun = transactions_.beginTransaction(descriptor->displayName.empty() ? id.value() : descriptor->displayName);
123 if (!begun.ok()) return Result<EditorValue>::failure(begun.status());
124 }
125
126 CommandContext commandContext;
127 commandContext.session = this;
128 commandContext.profile = &hostProfile_;
129 commandContext.source = source;
130 if (IEditableTarget* currentTarget = target()) {
131 commandContext.target = TargetId(currentTarget->targetId());
132 commandContext.targetRevision = currentTarget->revision();
133 }
134
135 Result<EditorValue> result = commandService_->execute(id, commandContext, payload);
136 if (ownsTransaction) {
137 if (result.ok()) {
138 auto committed = transactions_.commitTransaction();
139 if (!committed.ok()) {
140 auto discarded = transactions_.rollbackTransaction();
141 if (!discarded.ok()) {
142 std::vector<EditorDiagnostic> diagnostics = committed.diagnostics();
143 appendProjectedDiagnostics(diagnostics, discarded.status());
145 eve::Status(EditorStatus::Failed, std::move(diagnostics)));
146 }
147 return Result<EditorValue>::failure(committed.status());
148 }
149 } else {
150 auto discarded = transactions_.rollbackTransaction();
151 if (!discarded.ok()) {
152 std::vector<EditorDiagnostic> diagnostics = result.diagnostics();
153 appendProjectedDiagnostics(diagnostics, discarded.status());
155 eve::Status(EditorStatus::Failed, std::move(diagnostics)));
156 }
157 }
158 }
159 return result;
160}
161
163 EditorContextSnapshot snapshot;
164 snapshot.session = sessionId_;
165 snapshot.host = hostProfile_.kind();
166 if (IEditableTarget* currentTarget = target()) {
167 snapshot.target = TargetId(currentTarget->targetId());
168 snapshot.targetRevision = currentTarget->revision();
169 snapshot.targetGeneration = targetGeneration_;
170 }
171 return snapshot;
172}
173
176 std::optional<Revision> expectedRevision) const {
177 if (!commandService_)
178 return eve::editing::failed<CommandPlan>(EditorStatus::Failed, RuleId("editor.command.missing-service"),
179 "Editor session has no command service");
181 request.id = id;
182 request.payload = payload;
183 request.source = source;
184 request.context = contextSnapshot();
185 request.expectedRevision = expectedRevision;
186 request.dryRun = true;
187 return commandService_->plan(request, hostProfile_);
188}
189
192 if (!commandService_)
193 return eve::editing::failed<TransactionReceipt>(EditorStatus::Failed, RuleId("editor.command.missing-service"),
194 "Editor session has no command service");
196 request.id = plan.command;
197 request.payload = payload;
198 request.source = source;
199 request.context = contextSnapshot();
200 if (request.context.target != plan.target || request.context.targetRevision != plan.baseRevision ||
201 request.context.targetGeneration != plan.targetGeneration)
202 return eve::editing::failed<TransactionReceipt>(EditorStatus::Conflict, RuleId("editor.command.stale-plan"),
203 "The live target binding no longer matches this plan");
204 request.expectedRevision = plan.baseRevision;
205 return commandService_->executePlan(request, plan, hostProfile_);
206}
207
210 TransactionReceipt receipt;
211 receipt.id = TransactionId((sessionId_.empty() ? std::string("editor.session") : sessionId_.value()) +
212 ".transaction." + std::to_string(++receiptSequence_));
213 IEditableTarget* currentTarget = target();
214 receipt.beforeRevision = currentTarget ? currentTarget->revision() : 0;
216 currentTarget = target();
217 receipt.afterRevision = currentTarget ? currentTarget->revision() : receipt.beforeRevision;
218 receipt.diagnostics = command.diagnostics();
219 receipt.state = command.ok() ? TransactionState::Committed
220 : (command.code() == EditorStatus::Conflict ? TransactionState::Conflicted
221 : TransactionState::Rejected);
222 if (!command.ok()) return Result<TransactionReceipt>::failure(command.status());
224 std::move(receipt), eve::Status(command.code(), command.diagnostics()));
225}
226
227std::vector<CommandDescriptor> EditorSession::availableCommands() const {
228 return commandService_ ? commandService_->commands(hostProfile_) : std::vector<CommandDescriptor>{};
229}
230
232 std::optional<Revision> expectedRevision) {
233 Result<CommandPlan> planned = planCommand(id, payload, source, expectedRevision);
234 if (!planned.ok()) return Result<PlanId>::failure(planned.status());
235 const PlanId planId = planned.value().id;
236 retainedPlans_.erase(std::remove_if(retainedPlans_.begin(), retainedPlans_.end(),
237 [&](const RetainedPlan& retained) { return retained.plan.id == planId; }),
238 retainedPlans_.end());
239 retainedPlans_.push_back({std::move(planned.value()), payload});
240 return eve::editing::applied<PlanId>(planId);
241}
242
244 const auto found = std::find_if(retainedPlans_.begin(), retainedPlans_.end(),
245 [&](const RetainedPlan& retained) { return retained.plan.id == id; });
246 if (found == retainedPlans_.end())
247 return eve::editing::failed<TransactionReceipt>(EditorStatus::NotFound, RuleId("editor.command.plan-not-found"),
248 "Retained command plan was not found");
249 Result<TransactionReceipt> result = executePlan(found->plan, found->payload, source);
250 if (result.ok()) retainedPlans_.erase(found);
251 return result;
252}
253
255 const auto found = std::find_if(retainedPlans_.begin(), retainedPlans_.end(),
256 [&](const RetainedPlan& retained) { return retained.plan.id == id; });
257 if (found == retainedPlans_.end())
258 return eve::editing::failed<void>(EditorStatus::NotFound, RuleId("editor.command.plan-not-found"),
259 "Retained command plan was not found");
260 retainedPlans_.erase(found);
261 return eve::editing::applied<void>();
262}
263
264void EditorSession::clearRetainedPlans() { retainedPlans_.clear(); }
265
267 if (documents)
268 bindDocumentServices(*documents, autosave);
269 else
271}
272
274 documentService_ = &documents;
275 autosaveService_ = autosave;
277}
278
281 documentService_ = nullptr;
282 autosaveService_ = nullptr;
283}
284
286 if (!documentService_)
287 return eve::editing::failed<DocumentSnapshot>(EditorStatus::Failed,
288 RuleId("editor.session.missing-document-service"),
289 "Editor session has no document service");
290 Result<DocumentSnapshot> snapshot = documentService_->snapshot(document);
291 if (!snapshot.ok() || !snapshot.ok()) return snapshot;
292 activeDocument_ = document;
293 autosaveElapsed_ = 0.f;
294 externalPollElapsed_ = 0.f;
295 lastAutosavedRevision_ = snapshot.value().revision.saved;
296 return snapshot;
297}
298
300 activeDocument_ = DocumentId();
301 autosaveElapsed_ = 0.f;
302 externalPollElapsed_ = 0.f;
303 lastAutosavedRevision_ = 0;
304}
305
307 std::optional<Revision> expectedRevision) {
308 if (!documentService_ || activeDocument_.empty())
309 return eve::editing::failed<DocumentSnapshot>(EditorStatus::Failed,
310 RuleId("editor.session.no-active-document"),
311 "Editor session has no active document");
312 return documentService_->edit(activeDocument_, std::move(content), expectedRevision);
313}
314
316 if (!documentService_ || activeDocument_.empty())
317 return eve::editing::failed<DocumentSnapshot>(EditorStatus::Failed,
318 RuleId("editor.session.no-active-document"),
319 "Editor session has no active document");
320 Result<SaveTicket> ticket = documentService_->requestSave(activeDocument_);
321 if (!ticket.ok()) return Result<DocumentSnapshot>::failure(ticket.status());
322 Result<DocumentSnapshot> result = documentService_->executeSave(ticket.value());
323 if (result.ok()) {
324 autosaveElapsed_ = 0.f;
325 if (!result.value().dirty()) lastAutosavedRevision_ = result.value().revision.edit;
326 }
327 return result;
328}
329
331 if (!documentService_ || !autosaveService_ || activeDocument_.empty())
332 return eve::editing::failed<StoredDocument>(EditorStatus::Failed,
333 RuleId("editor.session.missing-autosave-service"),
334 "Editor session has no active autosave service");
335 Result<DocumentSnapshot> snapshot = documentService_->snapshot(activeDocument_);
336 Result<EditorValue> content = documentService_->content(activeDocument_);
337 if (!snapshot.ok() || !snapshot.ok() || !content.ok() || !content.ok())
338 return eve::editing::failed<StoredDocument>(EditorStatus::Failed,
339 RuleId("editor.session.autosave-snapshot-failed"),
340 "Active document could not be captured for autosave");
341 Result<StoredDocument> result = autosaveService_->writeDraft(snapshot.value(), content.value());
342 if (result.ok()) {
343 lastAutosavedRevision_ = snapshot.value().revision.edit;
344 autosaveElapsed_ = 0.f;
345 }
346 return result;
347}
348
350 if (!documentService_ || activeDocument_.empty())
351 return eve::editing::failed<DocumentSnapshot>(EditorStatus::Failed,
352 RuleId("editor.session.no-active-document"),
353 "Editor session has no active document");
354 externalPollElapsed_ = 0.f;
355 return documentService_->reconcileExternal(activeDocument_);
356}
357
358void EditorSession::setAutosaveInterval(float seconds) { autosaveInterval_ = std::max(0.f, seconds); }
359
361 externalPollInterval_ = std::max(0.f, seconds);
362}
363
365 try {
366 deactivateCurrent();
367 } catch (...) {
368 }
369 try {
370 releaseTargetBinding();
371 } catch (...) {
372 }
373}
374
376 if (!tool || tool->descriptor().id.empty()) return false;
377 for (auto* registered : tools_) {
378 if (registered == tool || registered->descriptor().id == tool->descriptor().id) return false;
379 }
380 tools_.push_back(tool);
381 return true;
382}
383
384bool EditorSession::removeTool(const std::string& id) {
385 auto it = std::find_if(tools_.begin(), tools_.end(),
386 [&](const IEditorTool* tool) { return tool && tool->descriptor().id == id; });
387 if (it == tools_.end()) return false;
388 const bool wasActive = *it == activeTool_;
389 tools_.erase(it);
390 if (wasActive) deactivateCurrent();
391 return true;
392}
393
395 tools_.clear();
396 deactivateCurrent();
397}
398
399int EditorSession::getToolCount() const { return static_cast<int>(tools_.size()); }
400
402 if (index < 0 || index >= static_cast<int>(tools_.size())) return nullptr;
403 return tools_[static_cast<size_t>(index)];
404}
405
406IEditorTool* EditorSession::findTool(const std::string& id) const {
407 for (auto* tool : tools_) {
408 if (tool && tool->descriptor().id == id) return tool;
409 }
410 return nullptr;
411}
412
413bool EditorSession::activateTool(const std::string& id) {
414 if (id.empty()) {
415 deactivateCurrent();
416 return true;
417 }
418 IEditorTool* next = findTool(id);
419 if (!next) return false;
420 if (next == activeTool_) return true;
421 deactivateCurrent();
422 next = findTool(id);
423 if (!next) return false;
424 activeTool_ = next;
425 ++toolGeneration_;
426 try {
427 activeTool_->activate(context_);
428 } catch (...) {
429 if (activeTool_ == next) {
430 activeTool_ = nullptr;
431 capturedPointerId_ = -1;
432 ++toolGeneration_;
433 }
434 throw;
435 }
436 return true;
437}
438
439std::string EditorSession::activeToolId() const { return activeTool_ ? activeTool_->descriptor().id : std::string{}; }
440
442 if (!activeTool_) return ToolResponse::ignored();
443 if (capturedPointerId_ >= 0 && event.pointerId != capturedPointerId_) {
444 return ToolResponse::ignored();
445 }
446 IEditorTool* const dispatchedTool = activeTool_;
447 const std::uint64_t generation = toolGeneration_;
448 ToolResponse response = dispatchedTool->pointerEvent(context_, event);
449 if (activeTool_ != dispatchedTool || toolGeneration_ != generation)
450 return {response.handled, false, false};
451 if (response.capturePointer && capturedPointerId_ < 0) capturedPointerId_ = event.pointerId;
452 if (response.releasePointer && capturedPointerId_ == event.pointerId) capturedPointerId_ = -1;
453 if (event.phase == EditorPointerEvent::Phase::Cancel && capturedPointerId_ == event.pointerId) {
454 capturedPointerId_ = -1;
455 }
456 return response;
457}
458
460 return activeTool_ ? activeTool_->keyEvent(context_, event) : ToolResponse::ignored();
461}
462
463void EditorSession::update(float dt) {
464 if (activeTool_) activeTool_->update(context_, dt);
465 if (!documentService_ || activeDocument_.empty() || dt <= 0.f) return;
466
467 if (externalPollInterval_ > 0.f) {
468 externalPollElapsed_ += dt;
469 if (externalPollElapsed_ >= externalPollInterval_) (void)pollDocumentChanges();
470 }
471
472 Result<DocumentSnapshot> snapshot = documentService_->snapshot(activeDocument_);
473 if (!snapshot.ok() || !snapshot.value().dirty()) {
474 autosaveElapsed_ = 0.f;
475 return;
476 }
477 if (!autosaveService_ || autosaveInterval_ <= 0.f ||
478 snapshot.value().revision.edit == lastAutosavedRevision_)
479 return;
480 autosaveElapsed_ += dt;
481 if (autosaveElapsed_ >= autosaveInterval_) (void)autosaveDocument();
482}
483
485 if (activeTool_) activeTool_->drawOverlay(context_, overlay);
486}
487
489 if (activeTool_) activeTool_->inspect(context_, inspector);
490}
491
493 capturedPointerId_ = -1;
494 if (activeTool_) activeTool_->cancel(context_);
495}
496
497void EditorSession::deactivateCurrent() {
498 IEditorTool* current = activeTool_;
499 activeTool_ = nullptr;
500 capturedPointerId_ = -1;
501 if (!current) return;
502 ++toolGeneration_;
503
504 std::exception_ptr failure;
505 try {
506 current->cancel(context_);
507 } catch (...) {
508 failure = std::current_exception();
509 }
510 try {
511 current->deactivate(context_);
512 } catch (...) {
513 if (!failure) failure = std::current_exception();
514 }
515 if (failure) std::rethrow_exception(failure);
516}
517
518} // namespace eve::editor
LogicalId target
Value::Object payload
std::string descriptor
const GltfImportRequest & request
std::weak_ptr< const void > lifetime
std::string id
Definition PlayHost.cpp:108
std::uint32_t generation
bool found
double current
uint32_t index
const UnitySourceAsset & source
bool ok() const noexcept
Whether this result represents a non-failure outcome.
Definition Result.h:480
const std::vector< Diagnostic > & diagnostics() const noexcept
Inspect all diagnostics; this counts as checking the Result.
Definition Result.h:501
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
const T & value() const &
Borrow the value from a const lvalue after checking success.
Definition Result.h:308
const std::vector< Diagnostic > & diagnostics() const noexcept
Inspect all diagnostics; this counts as checking the Result.
Definition Result.h:283
bool ok() const noexcept
Whether this result represents a non-failure outcome.
Definition Result.h:255
StatusCode code() const noexcept
Inspect the stable operation code.
Definition Result.h:276
const Status & status() const noexcept
Inspect the structured operation status.
Definition Result.h:269
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
Structured status and zero or more diagnostics for an operation.
Definition Status.h:68
UUID-backed identifier adapter for legacy textual boundaries.
Definition Identity.h:314
const std::string & value() const noexcept
Returns the exact legacy or canonical compatibility spelling.
Definition Identity.h:362
bool empty() const noexcept
True when no compatibility spelling has been assigned.
Definition Identity.h:374
IEditableTarget public API.
virtual TargetId targetId() const =0
Target id.
Deterministic owning value tree shared by authoring hosts.
Autosave coordinator that never overwrites the formal document URI.
Result< StoredDocument > writeDraft(const DocumentSnapshot &snapshot, const EditorValue &content)
Write one revisioned draft under autosave://project/document.draft.
Document coordinator with revision-safe requestSave/executeSave sequencing.
Result< DocumentSnapshot > reconcileExternal(const DocumentId &document)
Reconcile one open document with the latest store value. Clean documents adopt external content; dirt...
Result< DocumentSnapshot > edit(const DocumentId &document, EditorValue content, std::optional< Revision > expectedRevision=std::nullopt)
Replace the working content using an optional expected edit revision.
Result< DocumentSnapshot > snapshot(const DocumentId &document) const
Return one metadata snapshot.
Result< DocumentSnapshot > executeSave(const SaveTicket &ticket)
Execute a captured save ticket without reading newer working content.
Result< EditorValue > content(const DocumentId &document) const
Return the current working content snapshot.
Result< SaveTicket > requestSave(const DocumentId &document)
Capture an exact content/revision pair for a later CAS save.
Result< void > evaluateChecked(EditorContext &context, IEditCommand &command)
Evaluate the chain and return structured allow/warning/reject diagnostics.
Result< EditorValue > execute(const CommandId &id, const CommandContext &context, const EditorValue &payload) const
Execute a command after payload and profile checks.
const CommandDescriptor * find(const CommandId &id) const
Return command metadata or nullptr when it is not registered.
std::vector< CommandDescriptor > commands(const HostProfile &profile) const
Return descriptors visible to a host profile.
Result< TransactionReceipt > executePlan(const CommandRequest &request, const CommandPlan &plan, const HostProfile &profile) const
Execute a plan only when its lifetime, registration, policy and input bindings remain valid.
Result< CommandPlan > plan(const CommandRequest &request, const HostProfile &profile) const
Produce a side-effect-free plan bound to the target, command generation, payload and source.
bool execute(std::unique_ptr< IEditCommand > command) const
Send a command through constraints into the active transaction.
Result< void > executeChecked(std::unique_ptr< IEditCommand > command) const
Send a command without discarding validation or transaction diagnostics.
EditorTransactions & transactions() const
Transactions.
IEditableTarget * target() const
Target currently bound to the session.
IEditableTarget * target() const
Return the live borrowed target, or null after an explicit or tracked unbind.
Result< StoredDocument > autosaveDocument()
Write the active dirty revision to its separate autosave draft.
void clearTarget()
Clear the active target and invalidate retained plans derived from it.
IEditorTool * findTool(const std::string &id) const
Finds tool.
void unbindDocument()
Stop coordinating the active document without closing it.
bool addTool(IEditorTool *tool)
Register a tool. Returns false for null or duplicate id/pointer.
bool execute(std::unique_ptr< IEditCommand > command)
Validate then execute a command in the active transaction.
EditorSession()
Editor session.
bool removeTool(const std::string &id)
Remove a registered tool by id, deactivating it when necessary.
IEditorTool * getTool(int index) const
Returns the tool.
EditorContextSnapshot contextSnapshot() const
Capture target revision and host identity for delayed command work.
ToolResponse dispatchPointer(const EditorPointerEvent &event)
Route input to the active tool and apply pointer-capture response.
ToolResponse dispatchKey(const EditorKeyEvent &event)
Route keyboard input to the active tool.
void clearDocumentServices()
Clear document service bindings and unbind the active document.
EditorTransactions & transactions()
Transactions.
Result< void > cancelRetainedPlan(const PlanId &id)
Discard one retained plan without executing it.
void drawOverlay(IEditorOverlay &overlay)
Ask the active tool to emit viewport feedback.
Result< TransactionReceipt > executeCommandReceipt(const CommandId &id, const EditorValue &payload={}, CommandSource source=CommandSource::Api)
Execute a legacy-compatible command and return a V2 transaction receipt.
bool activateTool(const std::string &id)
Activate a registered tool by id. Empty id deactivates all tools.
void clearRetainedPlans()
Discard all retained plans, for example after replacing a document or target.
void update(float dt)
Update the active tool.
Result< void > executeChecked(std::unique_ptr< IEditCommand > command)
Validate and execute a command while preserving constraint and transaction diagnostics.
Result< CommandPlan > planCommand(const CommandId &id, const EditorValue &payload={}, CommandSource source=CommandSource::Api, std::optional< Revision > expectedRevision=std::nullopt) const
Plan a registered command without applying target mutations.
Result< DocumentSnapshot > pollDocumentChanges()
Detect external disk changes, adopting only when the document is clean.
Result< DocumentSnapshot > bindDocument(const DocumentId &document)
Select an already-open document for save, autosave and conflict polling.
Result< TransactionReceipt > executeRetainedPlan(const PlanId &id, CommandSource source=CommandSource::Api)
Execute a retained plan. Successful plans are consumed exactly once.
void inspect(IEditorInspector &inspector)
Ask the active tool to expose its configurable properties.
Result< DocumentSnapshot > editDocument(EditorValue content, std::optional< Revision > expectedRevision=std::nullopt)
Replace active working content using optional optimistic edit revision.
void cancelActiveTool()
Cancel its gesture and clear pointer capture.
void clearTools()
Remove all tools and release any pointer capture.
Result< TransactionReceipt > executePlan(const CommandPlan &plan, const EditorValue &payload={}, CommandSource source=CommandSource::Api)
Execute a previously returned plan through its registered executor.
void setAutosaveInterval(float seconds)
Configure draft cadence.
void setExternalPollInterval(float seconds)
Configure external-store polling cadence.
~EditorSession() noexcept
Editor session.
void bindTarget(IEditableTarget &target)
Bind a caller-managed editable target available to every tool callback.
Result< EditorValue > executeCommand(const CommandId &id, const EditorValue &payload={}, CommandSource source=CommandSource::Api)
Execute a registered V2 command in this session.
std::string activeToolId() const
Active tool id.
int getToolCount() const
Returns the tool count.
std::vector< CommandDescriptor > availableCommands() const
Return commands visible through this session's host profile.
Result< DocumentSnapshot > saveDocument()
Persist the current active revision through the document CAS store.
void setDocumentServices(DocumentService *documents, AutosaveService *autosave=nullptr)
Bind non-owning persistence services used by the active document.
Result< PlanId > retainPlan(const CommandId &id, const EditorValue &payload={}, CommandSource source=CommandSource::Api, std::optional< Revision > expectedRevision=std::nullopt)
Plan a command and retain its immutable payload under the returned plan id.
void bindDocumentServices(DocumentService &documents, AutosaveService *autosave=nullptr)
Bind document services; documents must outlive this binding.
Coordinates editable targets, per-target histories and domain commands.
Executes, groups, rolls back and replays arbitrary edit commands.
eve::Result< TransactionId > beginTransaction(TransactionSpec specification)
Begin a canonical checked transaction.
eve::Result< void > rollbackTransaction()
Discard the active transaction and restore its preview state.
eve::Result< void > append(std::unique_ptr< IEditCommand > command)
Stage and preview one command without discarding diagnostics.
bool isActive() const
True when active.
eve::Result< EditorTransactionRecord > commitTransaction()
Commit the active transaction and return its complete record.
HostKind kind() const
Kind.
UI-independent property editor used by tools to expose settings.
Sink implemented by a 2D or 3D viewport to render tool feedback.
Protocol implemented by every editor tool.
Definition EditorTool.h:110
virtual void update(EditorContext &context, float dt)
Per-frame hook for an active tool.
Definition EditorTool.h:140
virtual void inspect(EditorContext &context, IEditorInspector &inspector)
Expose configurable settings through a host-provided inspector.
Definition EditorTool.h:152
virtual void drawOverlay(EditorContext &context, IEditorOverlay &overlay)
Emit renderer-independent feedback for the active viewport.
Definition EditorTool.h:146
virtual ToolResponse pointerEvent(EditorContext &context, const EditorPointerEvent &event)
Handle normalized pointer input.
Definition EditorTool.h:124
virtual ToolResponse keyEvent(EditorContext &context, const EditorKeyEvent &event)
Handle normalized keyboard input.
Definition EditorTool.h:132
virtual void activate(EditorContext &context)
Called exactly once when this tool becomes active.
Definition EditorTool.h:119
virtual void cancel(EditorContext &context)
Cancel the active gesture while keeping the tool selected.
Definition EditorTool.h:158
virtual const ToolDescriptor & descriptor() const =0
Stable tool identity and presentation metadata.
CommandSource
Source that initiated an authoring command.
void appendProjectedDiagnostics(std::vector< eve::Diagnostic > &destination, const eve::Status &status)
Append diagnostics while assembling a new immutable Result status.
eve::editing::TargetId TargetId
Definition EditorIds.h:29
eve::editing::RuleId RuleId
Definition EditorIds.h:32
eve::editing::TransactionId TransactionId
Definition EditorIds.h:34
eve::editing::DocumentId DocumentId
Definition EditorIds.h:40
CommandPlan public API.
std::uint64_t targetGeneration
Target lifetime generation captured while planning.
CommandRequest public API.
ContextSnapshot public API.
std::uint64_t targetGeneration
Monotonic lifetime generation of the bound target instance.
TransactionReceipt public API.
std::vector< Diagnostic > diagnostics
Immutable execution context captured for a synchronous command.
Presentation and execution metadata for a registered command.
Keyboard input normalized by the editor host.
Definition EditorTool.h:40
Pointer input normalized by an editor viewport adapter.
Definition EditorTool.h:20
Result returned by a tool after processing input.
Definition EditorTool.h:50
static ToolResponse ignored()
Ignored.
Definition EditorTool.h:56