mirror of
https://github.com/textmate/textmate.git
synced 2026-04-28 03:00:34 -04:00
Change document’s isOpen property to isLoaded
Since we do not load documents before the user selects them, e.g. after session restore or when opening multiple documents, it makes sense to have both an isOpen and isLoaded property, the former means “is shown somewhere in the UI” and would make it appear (e.g. in file browser) with close button etc., whereas the latter means that data has been loaded from disk, and we can safely access the buffer.
This commit is contained in:
@@ -35,7 +35,7 @@ OAK_DEBUG_VAR(AppController_Commands);
|
||||
{
|
||||
document::document_ptr doc = document::create();
|
||||
// TODO set language according to snippet’s scope selector
|
||||
doc->sync_open();
|
||||
doc->sync_load();
|
||||
document::show(doc); // If we call show() with a document that isn’t open then it will be loaded in the background, and show() will return before this has completed, meaning the next line may not target our new document.
|
||||
[[DocumentWindowController controllerForDocument:doc] performBundleItem:item];
|
||||
doc->close();
|
||||
|
||||
@@ -76,12 +76,12 @@ namespace odb // wrap in namespace to avoid clashing with other callbacks named
|
||||
|
||||
void handle_document_event (document::document_ptr document, event_t event)
|
||||
{
|
||||
if(event == did_change_open_status && !document->is_open())
|
||||
if(event == did_change_load_status && !document->is_loaded())
|
||||
send_event(kAEClosedFile);
|
||||
else if(event == did_save)
|
||||
send_event(kAEModifiedFile);
|
||||
|
||||
if(event == did_change_open_status && !document->is_open())
|
||||
if(event == did_change_load_status && !document->is_loaded())
|
||||
{
|
||||
document->remove_callback(this);
|
||||
delete this;
|
||||
|
||||
@@ -273,7 +273,7 @@ namespace // wrap in anonymous namespace to avoid clashing with other callbacks
|
||||
|
||||
void handle_document_event (document::document_ptr document, event_t event)
|
||||
{
|
||||
if(event == did_change_open_status && !document->is_open())
|
||||
if(event == did_change_load_status && !document->is_loaded())
|
||||
{
|
||||
D(DBF_RMateServer, bug("%p\n", this););
|
||||
close_and_delete(document.get());
|
||||
|
||||
@@ -165,10 +165,10 @@ namespace
|
||||
// TODO Add kqueue watching of documents
|
||||
}
|
||||
|
||||
if(!_did_open && _document->is_open() && !_document->document().isLoading)
|
||||
if(!_did_load && _document->is_loaded() && !_document->document().isLoading)
|
||||
{
|
||||
_document->sync_open();
|
||||
_did_open = true;
|
||||
_document->sync_load();
|
||||
_did_load = true;
|
||||
}
|
||||
|
||||
_document->document().keepBackupFile = YES;
|
||||
@@ -179,10 +179,10 @@ namespace
|
||||
if(_open_count == 1)
|
||||
_document->remove_callback(this);
|
||||
|
||||
if(--_open_count == 0 && _did_open)
|
||||
if(--_open_count == 0 && _did_load)
|
||||
{
|
||||
_document->close();
|
||||
_did_open = false;
|
||||
_did_load = false;
|
||||
}
|
||||
return _open_count == 0;
|
||||
}
|
||||
@@ -220,12 +220,12 @@ namespace
|
||||
__weak DocumentWindowController* _self;
|
||||
document::document_ptr _document;
|
||||
size_t _open_count = 0;
|
||||
bool _did_open = false;
|
||||
bool _did_load = false;
|
||||
};
|
||||
|
||||
static bool is_disposable (document::document_ptr const& doc)
|
||||
{
|
||||
return doc && !doc->is_modified() && !doc->is_on_disk() && doc->path() == NULL_STR && doc->is_open() && doc->buffer().empty();
|
||||
return doc && !doc->is_modified() && !doc->is_on_disk() && doc->path() == NULL_STR && doc->is_loaded() && doc->buffer().empty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -915,7 +915,7 @@ namespace
|
||||
[self insertDocuments:{ doc } atIndex:_selectedTabIndex + 1 selecting:doc andClosing:[self disposableDocument]];
|
||||
|
||||
// Using openAndSelectDocument: will move focus to OakTextView
|
||||
doc->sync_open();
|
||||
doc->sync_load();
|
||||
[self setSelectedDocument:doc];
|
||||
doc->close();
|
||||
|
||||
@@ -1227,7 +1227,7 @@ namespace
|
||||
id observerId = [[NSNotificationCenter defaultCenter] addObserverForName:OakDocumentWillShowAlertNotification object:document queue:nil usingBlock:^(NSNotification*){
|
||||
for(size_t i = 0; i < _documents.size(); ++i)
|
||||
{
|
||||
if(document.isOpen && _documents[i]->document() == document)
|
||||
if(document.isLoaded && _documents[i]->document() == document)
|
||||
{
|
||||
if(_selectedDocument != _documents[i])
|
||||
{
|
||||
@@ -1679,7 +1679,7 @@ namespace
|
||||
|
||||
- (void)setSelectedDocument:(document::document_ptr)newSelectedDocument
|
||||
{
|
||||
ASSERT(!newSelectedDocument || newSelectedDocument->is_open());
|
||||
ASSERT(!newSelectedDocument || newSelectedDocument->is_loaded());
|
||||
if(_selectedDocument == newSelectedDocument)
|
||||
{
|
||||
self.documentView.document = _selectedDocument->document();
|
||||
@@ -2677,7 +2677,7 @@ static NSUInteger DisableSessionSavingCount = 0;
|
||||
if(document->is_modified() || document->path() == NULL_STR)
|
||||
{
|
||||
doc[@"identifier"] = [NSString stringWithCxxString:document->identifier()];
|
||||
if(document->is_open())
|
||||
if(document->is_loaded())
|
||||
document->backup();
|
||||
}
|
||||
if(document->path() != NULL_STR)
|
||||
|
||||
@@ -228,7 +228,7 @@ NSString* const FFFindWasTriggeredByEnter = @"FFFindWasTriggeredByEnter";
|
||||
|
||||
if(OakDocument* doc = parent.document)
|
||||
{
|
||||
if(doc.isOpen)
|
||||
if(doc.isLoaded)
|
||||
{
|
||||
[doc performReplacements:replacements checksum:parent.match.checksum];
|
||||
}
|
||||
@@ -242,7 +242,7 @@ NSString* const FFFindWasTriggeredByEnter = @"FFFindWasTriggeredByEnter";
|
||||
|
||||
[doc saveModalForWindow:self.windowController.window completionHandler:^(OakDocumentIOResult result, NSString* errorMessage, oak::uuid_t const& filterUUID){
|
||||
// TODO Indicate failure when result != OakDocumentIOResultSuccess
|
||||
if(!doc.isOpen) // Ensure document is still closed
|
||||
if(!doc.isLoaded) // Ensure document is still closed
|
||||
doc.content = nil;
|
||||
}];
|
||||
}
|
||||
@@ -502,7 +502,7 @@ NSString* const FFFindWasTriggeredByEnter = @"FFFindWasTriggeredByEnter";
|
||||
- (void)didSelectResult:(FFResultNode*)item
|
||||
{
|
||||
OakDocument* doc = item.document;
|
||||
if(!doc.isOpen)
|
||||
if(!doc.isLoaded)
|
||||
doc.recentTrackingDisabled = YES;
|
||||
document::show(document::find(to_s(doc.identifier.UUIDString)), self.projectIdentifier ? oak::uuid_t(to_s(self.projectIdentifier)) : document::kCollectionAny, item.match.range, false);
|
||||
}
|
||||
|
||||
@@ -2637,7 +2637,7 @@ static void update_menu_key_equivalents (NSMenu* menu, std::multimap<std::string
|
||||
|
||||
if(doc)
|
||||
{
|
||||
if(!doc->is_open())
|
||||
if(!doc->is_loaded())
|
||||
doc->set_recent_tracking(false);
|
||||
|
||||
NSString* range = [info objectForKey:(options & find::backwards) ? @"lastMatchRange" : @"firstMatchRange"];
|
||||
|
||||
@@ -69,7 +69,7 @@ PUBLIC @interface OakDocument : NSObject
|
||||
@property (nonatomic) osx::authorization_t authorization;
|
||||
|
||||
@property (nonatomic, getter = isOnDisk) BOOL onDisk;
|
||||
@property (nonatomic, getter = isOpen, readonly) BOOL open;
|
||||
@property (nonatomic, getter = isLoaded, readonly) BOOL loaded;
|
||||
@property (nonatomic, getter = isLoading, readonly) BOOL loading;
|
||||
@property (nonatomic, getter = isInViewingMode) BOOL inViewingMode;
|
||||
@property (nonatomic, getter = isDocumentEdited, readonly) BOOL documentEdited;
|
||||
|
||||
@@ -221,7 +221,7 @@ NSString* OakDocumentBookmarkIdentifier = @"bookmark";
|
||||
return [NSSet setWithObjects:@"path", @"customName", @"untitledCount", nil];
|
||||
}
|
||||
|
||||
+ (NSSet*)keyPathsForValuesAffectingOpen
|
||||
+ (NSSet*)keyPathsForValuesAffectingLoaded
|
||||
{
|
||||
return [NSSet setWithObjects:@"openCount", nil];
|
||||
}
|
||||
@@ -479,7 +479,7 @@ NSString* OakDocumentBookmarkIdentifier = @"bookmark";
|
||||
self.observeSCMStatus = YES;
|
||||
}
|
||||
|
||||
if(self.isOpen)
|
||||
if(self.isLoaded)
|
||||
{
|
||||
self.onDisk = access([_path fileSystemRepresentation], F_OK) == 0;
|
||||
if(NSString* fileType = [self sniffFileType])
|
||||
@@ -495,7 +495,7 @@ NSString* OakDocumentBookmarkIdentifier = @"bookmark";
|
||||
return;
|
||||
|
||||
_fileType = newType;
|
||||
if(self.isOpen)
|
||||
if(self.isLoaded)
|
||||
{
|
||||
[self setBufferGrammarForCurrentFileType];
|
||||
[self updateSpellingSettings:YES andIndentSettings:YES];
|
||||
@@ -839,12 +839,12 @@ NSString* OakDocumentBookmarkIdentifier = @"bookmark";
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:OakDocumentDidSaveNotification object:self];
|
||||
}
|
||||
self.observeFileSystem = self.isOpen;
|
||||
self.observeFileSystem = self.isLoaded;
|
||||
}
|
||||
|
||||
- (void)saveModalForWindow:(NSWindow*)aWindow completionHandler:(void(^)(OakDocumentIOResult result, NSString* errorMessage, oak::uuid_t const& filterUUID))block
|
||||
{
|
||||
if(!self.isOpen && self.isDocumentEdited && _backupPath)
|
||||
if(!self.isLoaded && self.isDocumentEdited && _backupPath)
|
||||
{
|
||||
[self loadModalForWindow:aWindow completionHandler:^(OakDocumentIOResult result, NSString* errorMessage, oak::uuid_t const& filterUUID){
|
||||
if(result == OakDocumentIOResultSuccess)
|
||||
@@ -979,7 +979,7 @@ NSString* OakDocumentBookmarkIdentifier = @"bookmark";
|
||||
void(^_block)(OakDocumentIOResult result, NSString* path, encoding::type const& encoding, NSString* errorMessage, oak::uuid_t const& filterUUID);
|
||||
};
|
||||
|
||||
BOOL closeDocument = self.isOpen;
|
||||
BOOL closeDocument = self.isLoaded;
|
||||
if(closeDocument)
|
||||
++self.openCount;
|
||||
|
||||
@@ -1116,7 +1116,7 @@ NSString* OakDocumentBookmarkIdentifier = @"bookmark";
|
||||
return _icon;
|
||||
}
|
||||
|
||||
- (BOOL)isOpen { return _openCount != 0; }
|
||||
- (BOOL)isLoaded { return _openCount != 0; }
|
||||
- (BOOL)isDocumentEdited { return _revision != _savedRevision && (_onDisk || !_bufferEmpty); }
|
||||
- (BOOL)shouldSniffFileType { return settings_for_path(to_s(_virtualPath ?: _path), scope::scope_t(), to_s(_directory ?: [_path stringByDeletingLastPathComponent])).get(kSettingsFileTypeKey, NULL_STR) == NULL_STR; }
|
||||
|
||||
@@ -1204,7 +1204,7 @@ NSString* OakDocumentBookmarkIdentifier = @"bookmark";
|
||||
|
||||
- (void)enumerateSymbolsUsingBlock:(void(^)(text::pos_t const& pos, NSString* symbol))block
|
||||
{
|
||||
if(self.isOpen && _buffer)
|
||||
if(self.isLoaded && _buffer)
|
||||
{
|
||||
_buffer->wait_for_repair();
|
||||
for(auto const& pair : _buffer->symbols())
|
||||
@@ -1214,7 +1214,7 @@ NSString* OakDocumentBookmarkIdentifier = @"bookmark";
|
||||
|
||||
- (void)enumerateBookmarksUsingBlock:(void(^)(text::pos_t const& pos, NSString* excerpt))block
|
||||
{
|
||||
if(self.isOpen && _buffer)
|
||||
if(self.isLoaded && _buffer)
|
||||
{
|
||||
for(auto const& pair : _buffer->get_marks(0, _buffer->size(), to_s(OakDocumentBookmarkIdentifier)))
|
||||
{
|
||||
@@ -1226,7 +1226,7 @@ NSString* OakDocumentBookmarkIdentifier = @"bookmark";
|
||||
|
||||
- (void)enumerateBookmarksAtLine:(NSUInteger)line block:(void(^)(text::pos_t const& pos, NSString* type, NSString* payload))block
|
||||
{
|
||||
if(self.isOpen && _buffer)
|
||||
if(self.isLoaded && _buffer)
|
||||
{
|
||||
for(auto const& pair : _buffer->get_marks(_buffer->begin(line), _buffer->eol(line)))
|
||||
block(_buffer->convert(pair.first), to_ns(pair.second.first), to_ns(pair.second.second));
|
||||
@@ -1309,7 +1309,7 @@ NSString* OakDocumentBookmarkIdentifier = @"bookmark";
|
||||
std::map<std::string, std::string> captures;
|
||||
};
|
||||
|
||||
__block find::find_t f(to_s(searchString), options | (self.isOpen ? find::none : find::filesize_limit));
|
||||
__block find::find_t f(to_s(searchString), options | (self.isLoaded ? find::none : find::filesize_limit));
|
||||
__block std::vector<range_match_t> ranges;
|
||||
__block boost::crc_32_type crc32;
|
||||
__block size_t total = 0;
|
||||
@@ -1630,7 +1630,7 @@ NSString* OakDocumentBookmarkIdentifier = @"bookmark";
|
||||
{
|
||||
__weak __block id observerId = [[NSNotificationCenter defaultCenter] addObserverForName:NSApplicationDidBecomeActiveNotification object:NSApp queue:nil usingBlock:^(NSNotification*){
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:observerId];
|
||||
if(self.isOpen)
|
||||
if(self.isLoaded)
|
||||
[self importDocumentChanges:self];
|
||||
}];
|
||||
}
|
||||
@@ -1685,7 +1685,7 @@ NSString* OakDocumentBookmarkIdentifier = @"bookmark";
|
||||
|
||||
void show_content (std::string const& path, io::bytes_ptr content, std::map<std::string, std::string> const& attributes, encoding::type const& encoding, std::vector<oak::uuid_t> const& binaryImportFilters, std::vector<oak::uuid_t> const& textImportFilters)
|
||||
{
|
||||
if(!_self.isOpen)
|
||||
if(!_self.isLoaded)
|
||||
return;
|
||||
|
||||
ng::buffer_t& buffer = [_self buffer];
|
||||
@@ -1757,7 +1757,7 @@ NSString* OakDocumentBookmarkIdentifier = @"bookmark";
|
||||
|
||||
- (BOOL)performReplacements:(std::multimap<std::pair<size_t, size_t>, std::string> const&)someReplacements checksum:(uint32_t)crc32
|
||||
{
|
||||
if(self.isOpen)
|
||||
if(self.isLoaded)
|
||||
{
|
||||
OakDocumentEditor* documentEditor = self.documentEditors.firstObject ?: [OakDocumentEditor documentEditorWithDocument:self fontScaleFactor:1];
|
||||
[documentEditor performReplacements:someReplacements];
|
||||
|
||||
@@ -32,7 +32,7 @@ static int32_t const NSWrapColumnWindowWidth = 0;
|
||||
{
|
||||
if(self = [self init])
|
||||
{
|
||||
ASSERT(aDocument.isOpen);
|
||||
ASSERT(aDocument.isLoaded);
|
||||
|
||||
// TODO Get from somewhere else (settings?)
|
||||
bool scrollPastEnd = false;
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace document
|
||||
|
||||
OakDocument* document () { observer(); return _document; }
|
||||
|
||||
void sync_open (CFStringRef runLoopMode = kCFRunLoopDefaultMode);
|
||||
void sync_load (CFStringRef runLoopMode = kCFRunLoopDefaultMode);
|
||||
bool sync_save (CFStringRef runLoopMode = kCFRunLoopDefaultMode);
|
||||
|
||||
void show ();
|
||||
@@ -63,7 +63,7 @@ namespace document
|
||||
std::string file_type () const;
|
||||
ssize_t revision () const;
|
||||
std::string content () const;
|
||||
bool is_open () const;
|
||||
bool is_loaded () const;
|
||||
bool is_modified () const;
|
||||
bool is_on_disk () const;
|
||||
text::indent_t indent () const;
|
||||
@@ -120,7 +120,7 @@ namespace document
|
||||
{
|
||||
did_save,
|
||||
|
||||
did_change_open_status,
|
||||
did_change_load_status,
|
||||
did_change_modified_status,
|
||||
did_change_on_disk_status,
|
||||
did_change_path,
|
||||
|
||||
@@ -61,7 +61,7 @@ static std::map<std::string, document::document_t::callback_t::event_t> const Ob
|
||||
{ "path", document::document_t::callback_t::did_change_path },
|
||||
{ "onDisk", document::document_t::callback_t::did_change_on_disk_status },
|
||||
{ "fileType", document::document_t::callback_t::did_change_file_type },
|
||||
{ "open", document::document_t::callback_t::did_change_open_status },
|
||||
{ "loaded", document::document_t::callback_t::did_change_load_status },
|
||||
{ "documentEdited", document::document_t::callback_t::did_change_modified_status },
|
||||
{ "tabSize", document::document_t::callback_t::did_change_indent_settings, },
|
||||
{ "softTabs", document::document_t::callback_t::did_change_indent_settings, },
|
||||
@@ -179,7 +179,7 @@ namespace document
|
||||
std::string document_t::file_type () const { return to_s(_document.fileType); }
|
||||
ssize_t document_t::revision () const { return _document.revision; }
|
||||
std::string document_t::content () const { return to_s(_document.content); }
|
||||
bool document_t::is_open () const { return _document.isOpen; }
|
||||
bool document_t::is_loaded () const { return _document.isLoaded; }
|
||||
bool document_t::is_modified () const { return _document.isDocumentEdited; }
|
||||
bool document_t::is_on_disk () const { return _document.isOnDisk; }
|
||||
text::indent_t document_t::indent () const { return text::indent_t(_document.tabSize, SIZE_T_MAX, _document.softTabs); }
|
||||
@@ -206,7 +206,7 @@ namespace document
|
||||
ng::buffer_t& document_t::buffer () { return [_document buffer]; }
|
||||
ng::undo_manager_t& document_t::undo_manager () { return [_document undoManager]; }
|
||||
|
||||
void document_t::sync_open (CFStringRef runLoopMode)
|
||||
void document_t::sync_load (CFStringRef runLoopMode)
|
||||
{
|
||||
observer(); // Create OakDocumentObserver if it does not already exist
|
||||
|
||||
@@ -264,7 +264,7 @@ namespace document
|
||||
void document_t::close ()
|
||||
{
|
||||
[_document close];
|
||||
if(!_document.isOpen && !_observer.hasCallbacks)
|
||||
if(!_document.isLoaded && !_observer.hasCallbacks)
|
||||
_observer = nil;
|
||||
}
|
||||
|
||||
@@ -291,7 +291,7 @@ namespace document
|
||||
void document_t::remove_callback (callback_t* callback)
|
||||
{
|
||||
[_observer removeCallback:callback];
|
||||
if(!_document.isOpen && !_observer.hasCallbacks)
|
||||
if(!_document.isLoaded && !_observer.hasCallbacks)
|
||||
_observer = nil;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ void test_grammar_picking ()
|
||||
{
|
||||
document::document_ptr doc = document::create();
|
||||
doc->set_file_type("source.c");
|
||||
doc->sync_open();
|
||||
doc->sync_load();
|
||||
OAK_ASSERT_EQ(to_s(doc->buffer().scope(0).left), "source.c");
|
||||
doc->close();
|
||||
}
|
||||
@@ -16,7 +16,7 @@ void test_modeline_file ()
|
||||
jail.set_content("source-file", "// -*- Mode: C -*-\n\nint main () { return 0; }\n");
|
||||
|
||||
document::document_ptr doc = document::create(jail.path("source-file"));
|
||||
doc->sync_open();
|
||||
doc->sync_load();
|
||||
OAK_ASSERT_EQ(to_s(doc->buffer().scope(0).left), "source.c");
|
||||
OAK_ASSERT_EQ(doc->file_type(), "source.c");
|
||||
doc->close();
|
||||
@@ -25,7 +25,7 @@ void test_modeline_file ()
|
||||
void test_modeline_buffer ()
|
||||
{
|
||||
document::document_ptr doc = document::from_content("// -*- Mode: C -*-\n\nint main () { return 0; }\n");
|
||||
doc->sync_open();
|
||||
doc->sync_load();
|
||||
OAK_ASSERT_EQ(to_s(doc->buffer().scope(0).left), "source.c");
|
||||
OAK_ASSERT_EQ(doc->file_type(), "source.c");
|
||||
doc->close();
|
||||
|
||||
@@ -20,7 +20,7 @@ void test_replace_single_line ()
|
||||
replacements.insert(std::make_pair(std::make_pair(12, 17), "charum"));
|
||||
replacements.insert(std::make_pair(std::make_pair(28, 39), "abetarda"));
|
||||
doc->replace(replacements, crc32);
|
||||
doc->sync_open();
|
||||
doc->sync_load();
|
||||
OAK_ASSERT_EQ(doc->content(), "Lorem ipsum charum sit amet, abetarda adipisicing elit.");
|
||||
doc->close();
|
||||
}
|
||||
@@ -34,7 +34,7 @@ void test_replace_multiple_lines ()
|
||||
std::multimap<std::pair<size_t, size_t>, std::string> replacements;
|
||||
replacements.insert(std::make_pair(std::make_pair(4, 7), "Jazz"));
|
||||
doc->replace(replacements, crc32);
|
||||
doc->sync_open();
|
||||
doc->sync_load();
|
||||
OAK_ASSERT_EQ(doc->content(), "Foo\nJazz\nFud\n");
|
||||
doc->close();
|
||||
}
|
||||
@@ -66,7 +66,7 @@ void test_replace_content_changed ()
|
||||
document::document_ptr doc = document::create(jail.path("test.txt"));
|
||||
OAK_ASSERT(!doc->replace({ { { 0, 3 }, "Fud" } }, crc32 ^ 0xDEADBEEF));
|
||||
|
||||
doc->sync_open();
|
||||
doc->sync_load();
|
||||
OAK_ASSERT_EQ(doc->content(), "Foo\nBar\n");
|
||||
doc->close();
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ void test_bookmarks ()
|
||||
path::set_attr(jail.path("test.txt"), "com.macromates.bookmarks", "( '1:1', '1:8', '4:2' )");
|
||||
|
||||
document::document_ptr doc = document::create(jail.path("test.txt"));
|
||||
doc->sync_open();
|
||||
doc->sync_load();
|
||||
|
||||
std::map<size_t, std::string> marks = doc->buffer().get_marks(0, doc->buffer().size(), kBookmarkIdentifier);
|
||||
OAK_ASSERT_EQ(marks.size(), 3);
|
||||
@@ -26,7 +26,7 @@ void test_selection ()
|
||||
path::set_attr(jail.path("test.txt"), "com.macromates.selectionRange", "2:2&3:1");
|
||||
|
||||
document::document_ptr doc = document::create(jail.path("test.txt"));
|
||||
doc->sync_open();
|
||||
doc->sync_load();
|
||||
|
||||
OAK_ASSERT_EQ(doc->selection(), "2:2&3:1");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user