Revision: 28467
          http://sourceforge.net/p/bibdesk/svn/28467
Author:   hofman
Date:     2023-11-28 17:11:45 +0000 (Tue, 28 Nov 2023)
Log Message:
-----------
Add completions for auto-complete when adding items to a document. Also remove 
field values for completion when they are changed or itemas are removed, so 
erroneous strings are not kept as completion. Use counted sets to hold the 
completion strings, so strings remain when overwritten while another item has 
the value.

Modified Paths:
--------------
    trunk/bibdesk/BDSKBibTeXParser.m
    trunk/bibdesk/BDSKCompletionManager.h
    trunk/bibdesk/BDSKCompletionManager.m
    trunk/bibdesk/BibDocument.m
    trunk/bibdesk/BibItem.m

Modified: trunk/bibdesk/BDSKBibTeXParser.m
===================================================================
--- trunk/bibdesk/BDSKBibTeXParser.m    2023-11-26 17:36:32 UTC (rev 28466)
+++ trunk/bibdesk/BDSKBibTeXParser.m    2023-11-28 17:11:45 UTC (rev 28467)
@@ -56,7 +56,6 @@
 #import "BDSKGroupsArray.h"
 #import "NSScanner_BDSKExtensions.h"
 #import "NSError_BDSKExtensions.h"
-#import "BDSKCompletionManager.h"
 #import "NSData_BDSKExtensions.h"
 #import "CFString_BDSKExtensions.h"
 #import "NSDictionary_BDSKExtensions.h"
@@ -596,7 +595,6 @@
         [authors addObject:anAuthor];
         [anAuthor release];
     }
-    [[BDSKCompletionManager sharedManager] addNamesForCompletion:authors];
        CFRelease(names);
        return authors;
 }
@@ -1092,10 +1090,6 @@
         }
         
         if (fieldName && fieldValue) {
-            // add the expanded values to the autocomplete dictionary; authors 
are handled elsewhere
-            if ([fieldName isPersonField] == NO)
-                [[BDSKCompletionManager sharedManager] addString:fieldValue 
forCompletionEntry:fieldName];
-            
             [dictionary setObject:fieldValue forKey:fieldName];
         } else {
             hadProblems = YES;
@@ -1134,8 +1128,6 @@
             if ([crossref isCaseInsensitiveEqual:citeKey])
                 [dictionary setObject:[NSString stringWithFormat:@"(%@)", 
crossref] forKey:BDSKCrossrefString];
             
-            [[BDSKCompletionManager sharedManager] addString:citeKey 
forCompletionEntry:BDSKCrossrefString];
-            
             BibItem *newBI = [[BibItem alloc] initWithType:entryType
                                                    citeKey:citeKey
                                                  pubFields:dictionary

Modified: trunk/bibdesk/BDSKCompletionManager.h
===================================================================
--- trunk/bibdesk/BDSKCompletionManager.h       2023-11-26 17:36:32 UTC (rev 
28466)
+++ trunk/bibdesk/BDSKCompletionManager.h       2023-11-28 17:11:45 UTC (rev 
28467)
@@ -46,8 +46,12 @@
 
 + (id)sharedManager;
 
+- (void)addString:(NSString *)string forCompletionEntry:(NSString *)entry;
+- (void)removeString:(NSString *)string forCompletionEntry:(NSString *)entry;
 - (void)addNamesForCompletion:(NSArray *)authors;
-- (void)addString:(NSString *)string forCompletionEntry:(NSString *)entry;
+- (void)removeNamesForCompletion:(NSArray *)authors;
+- (void)addCompletionsFromItems:(NSArray *)items;
+- (void)removeCompletionsFromItems:(NSArray *)items;
 
 - (NSRange)entry:(NSString *)entry rangeForUserCompletion:(NSRange)charRange 
ofString:(NSString *)fullString;
 - (NSArray *)entry:(NSString *)entry completions:(NSArray *)words 
forPartialWordRange:(NSRange)charRange ofString:(NSString *)fullString 
indexOfSelectedItem:(NSInteger *)index;

Modified: trunk/bibdesk/BDSKCompletionManager.m
===================================================================
--- trunk/bibdesk/BDSKCompletionManager.m       2023-11-26 17:36:32 UTC (rev 
28466)
+++ trunk/bibdesk/BDSKCompletionManager.m       2023-11-28 17:11:45 UTC (rev 
28467)
@@ -39,10 +39,10 @@
 #import "BDSKCompletionManager.h"
 #import "BDSKStringConstants.h"
 #import "BDSKTypeManager.h"
-#import "NSArray_BDSKExtensions.h"
-#import "CFString_BDSKExtensions.h"
 #import "NSString_BDSKExtensions.h"
+#import "BDSKComplexString.h"
 #import "BibAuthor.h"
+#import "BibItem.h"
 
 
 @implementation BDSKCompletionManager
@@ -67,7 +67,7 @@
 - (NSMutableSet *)setForCompletionEntry:(NSString *)entry {
        NSMutableSet *set = [autoCompletionDict objectForKey:entry];
     if (set == nil) {
-        set = [[NSMutableSet alloc] initWithCapacity:500];
+        set = [[NSCountedSet alloc] init];
         [autoCompletionDict setObject:set forKey:entry];
         [set release];
     }
@@ -74,33 +74,19 @@
     return set;
 }
 
-- (void)addNamesForCompletion:(NSArray *)authors {
-    NSMutableSet *nameSet = [self setForCompletionEntry:BDSKAuthorString];
-    for (BibAuthor *author in authors) {
-        NSString *name = [author originalName];
-        if ([name isComplex])
-            name = [NSString stringWithString:name];
-        [nameSet addObject:name];
-        NSString *lastName = [[author lastName] stringByRemovingCurlyBraces];
-        if (lastName && [[name stringByRemovingCurlyBraces] 
hasCaseInsensitivePrefix:lastName] == NO)
-            [lastNamesDict setObject:lastName forKey:name];
-    }
-}
-
-- (void)addString:(NSString *)string forCompletionEntry:(NSString *)entry{
+- (void)addString:(NSString *)string forCompletionEntry:(NSString *)entry {
     
-       if (BDIsEmptyString((CFStringRef)entry) || [entry isNumericField] || 
[entry isURLField] || [entry isPersonField] || [entry isCitationField] || 
[entry hasPrefix:@"Bdsk-"])      
+    if ([NSString isEmptyString:entry] || [entry isNumericField] || [entry 
isURLField] || [entry isPersonField] || [entry isNoteField] || [entry 
isCitationField] || [entry hasPrefix:@"Bdsk-"])
                return;
 
     if ([entry isEqualToString:BDSKBooktitleString])   
                entry = BDSKTitleString;
        
-       NSMutableSet *completionSet = [self setForCompletionEntry:entry];
+    NSMutableSet *completionSet = [self setForCompletionEntry:entry];
     
     // more efficient for the splitting and checking functions
     // also adding complex strings can lead to a crash after the containing 
document closes
-    if ([string isComplex])
-        string = [NSString stringWithString:string];
+    string = [string expandedString];
 
     if ([entry isSingleValuedField]) { // add the whole string 
         [completionSet addObject:[string 
stringByCollapsingAndTrimmingCharactersInSet:[NSCharacterSet 
whitespaceCharacterSet]]];
@@ -116,6 +102,100 @@
     }
 }
 
+- (void)removeString:(NSString *)string forCompletionEntry:(NSString *)entry {
+    
+    if ([NSString isEmptyString:entry] || [entry isNumericField] || [entry 
isURLField] || [entry isPersonField] || [entry isNoteField] || [entry 
isCitationField] || [entry hasPrefix:@"Bdsk-"])
+        return;
+
+    if ([entry isEqualToString:BDSKBooktitleString])
+        entry = BDSKTitleString;
+    
+    NSMutableSet *completionSet = [autoCompletionDict objectForKey:entry];
+    
+    // more efficient for the splitting and checking functions
+    // also adding complex strings can lead to a crash after the containing 
document closes
+    string = [string expandedString];
+    
+    if ([entry isSingleValuedField]) { // remove the whole string
+        [completionSet removeObject:[string 
stringByCollapsingAndTrimmingCharactersInSet:[NSCharacterSet 
whitespaceCharacterSet]]];
+    } else {
+        NSCharacterSet *acSet = [[BDSKTypeManager sharedManager] 
separatorCharacterSetForField:entry];
+        if ([string rangeOfCharacterFromSet:acSet].location != NSNotFound) {
+            for (NSString *s in [string 
componentsSeparatedByCharactersInSet:acSet trimWhitespace:YES])
+                [completionSet removeObject:s];
+        } else if ([entry isEqualToString:BDSKKeywordsString]) {
+            // if it wasn't punctuated, try this; Elsevier uses "and" as a 
separator, and it's annoying to have the whole string autocomplete on you
+            for (NSString *s in [[string componentsSeparatedByString:@" and "] 
valueForKey:@"stringByCollapsingWhitespaceAndRemovingSurroundingWhitespace"])
+                [completionSet removeObject:s];
+        } else {
+            [completionSet removeObject:[string 
stringByCollapsingAndTrimmingCharactersInSet:[NSCharacterSet 
whitespaceCharacterSet]]];
+        }
+    }
+}
+
+- (void)addNamesForCompletion:(NSArray *)authors {
+    NSMutableSet *nameSet = [self setForCompletionEntry:BDSKAuthorString];
+    for (BibAuthor *author in authors) {
+        NSString *name = [author originalName];
+        if ([name isComplex])
+            name = [NSString stringWithString:name];
+        [nameSet addObject:name];
+        NSString *lastName = [[author lastName] stringByRemovingCurlyBraces];
+        if (lastName && [[name stringByRemovingCurlyBraces] 
hasCaseInsensitivePrefix:lastName] == NO)
+            [lastNamesDict setObject:lastName forKey:name];
+    }
+}
+
+- (void)removeNamesForCompletion:(NSArray *)authors {
+    NSMutableSet *nameSet = [autoCompletionDict objectForKey:BDSKAuthorString];
+    for (BibAuthor *author in authors) {
+        NSString *name = [author originalName];
+        if ([name isComplex])
+            name = [NSString stringWithString:name];
+        [nameSet removeObject:name];
+    }
+}
+
+- (void)addCompletionsFromItems:(NSArray *)items {
+    NSMutableArray *authors = [[NSMutableArray alloc] init];
+    for (BibItem *item in items) {
+        [[item pubFields] enumerateKeysAndObjectsUsingBlock:^(NSString *entry, 
NSString *string, BOOL *stop){
+                if ([NSString isEmptyString:string]) return;
+                if ([entry isPersonField])
+                    [authors addObjectsFromArray:[item 
peopleArrayForField:entry inherit:NO]];
+                else
+                    [self addString:string forCompletionEntry:entry];
+        }];
+        if ([authors count]) {
+            [self addNamesForCompletion:authors];
+            [authors removeAllObjects];
+        }
+        if ([item hasEmptyOrDefaultCiteKey] == NO)
+            [self addString:[item citeKey] 
forCompletionEntry:BDSKCrossrefString];
+    }
+    [authors release];
+}
+
+- (void)removeCompletionsFromItems:(NSArray *)items {
+    NSMutableArray *authors = [[NSMutableArray alloc] init];
+    for (BibItem *item in items) {
+        [[item pubFields] enumerateKeysAndObjectsUsingBlock:^(NSString *entry, 
NSString *string, BOOL *stop){
+            if ([NSString isEmptyString:string]) return;
+            if ([entry isPersonField])
+                [authors addObjectsFromArray:[item peopleArrayForField:entry 
inherit:NO]];
+            else
+                [self removeString:string forCompletionEntry:entry];
+        }];
+        if ([authors count]) {
+            [self removeNamesForCompletion:authors];
+            [authors removeAllObjects];
+        }
+        if ([item hasEmptyOrDefaultCiteKey] == NO)
+            [self removeString:[item citeKey] 
forCompletionEntry:BDSKCrossrefString];
+    }
+    [authors release];
+}
+
 - (NSRange)entry:(NSString *)entry rangeForUserCompletion:(NSRange)charRange 
ofString:(NSString *)fullString {
     NSCharacterSet *wsCharSet = [NSCharacterSet whitespaceCharacterSet];
     NSCharacterSet *acSet = [[BDSKTypeManager sharedManager] 
separatorCharacterSetForField:entry];
@@ -167,7 +247,7 @@
     
     NSSet *strings = [autoCompletionDict objectForKey:entry];
     NSString *string = nil;
-    NSMutableArray *completions = [NSMutableArray arrayWithCapacity:[strings 
count]];
+    NSMutableArray *completions = [NSMutableArray array];
     BOOL isAuthor = [entry isEqualToString:BDSKAuthorString];
 
     for (string in strings) {

Modified: trunk/bibdesk/BibDocument.m
===================================================================
--- trunk/bibdesk/BibDocument.m 2023-11-26 17:36:32 UTC (rev 28466)
+++ trunk/bibdesk/BibDocument.m 2023-11-28 17:11:45 UTC (rev 28467)
@@ -125,6 +125,7 @@
 #import "BDSKSaveAccessoryViewController.h"
 #import "NSObject_BDSKExtensions.h"
 #import "NSLayoutConstraint_BDSKExtensions.h"
+#import "BDSKCompletionManager.h"
 
 // these are the same as in Info.plist
 NSString *BDSKBibTeXDocumentType = @"BibTeX Database";
@@ -760,6 +761,10 @@
     
     [self endObserving];
     
+    // discard completions from temporary draft documents, but keep them from 
saved ones
+    if ([self fileURL] == nil)
+        [[BDSKCompletionManager sharedManager] 
removeCompletionsFromItems:publications];
+    
     // workaround for crash: to reproduce, create empty doc, hit cmd-n for new 
editor window, then cmd-q to quit, choose "don't save"; this results in an 
-undoManager message to the dealloced document
     [publications setValue:nil forKey:@"owner"];
     
@@ -928,10 +933,14 @@
 
 // This is not undoable!
 - (void)setPublications:(NSArray *)newPubs{
+    [[BDSKCompletionManager sharedManager] 
removeCompletionsFromItems:publications];
+    
     [publications setValue:nil forKey:@"owner"];
     [publications setArray:newPubs];
     [publications setValue:self forKey:@"owner"];
     
+    [[BDSKCompletionManager sharedManager] 
addCompletionsFromItems:publications];
+    
     [notesSearchIndex resetWithPublications:newPubs];
     [fileSearchController resetWithPublications:newPubs];
 }
@@ -945,6 +954,8 @@
     
        [pubs setValue:self forKey:@"owner"];
        
+    [[BDSKCompletionManager sharedManager] addCompletionsFromItems:pubs];
+
     NSDictionary *notifInfo = @{BDSKDocumentPublicationsKey:pubs};
        [[NSNotificationCenter defaultCenter] 
postNotificationName:BDSKDocumentDidAddItemNotification
                                                                                
                                object:self
@@ -974,7 +985,9 @@
     
        [publications removeObjectsAtIndexes:indexes];
        
-       [pubs setValue:nil forKey:@"owner"];
+    [[BDSKCompletionManager sharedManager] removeCompletionsFromItems:pubs];
+    
+    [pubs setValue:nil forKey:@"owner"];
     NSFileManager *fm = [NSFileManager defaultManager];
     for (BibItem *pub in pubs)
         [fm removeSpotlightCacheFileForCiteKey:[pub citeKey]];

Modified: trunk/bibdesk/BibItem.m
===================================================================
--- trunk/bibdesk/BibItem.m     2023-11-26 17:36:32 UTC (rev 28466)
+++ trunk/bibdesk/BibItem.m     2023-11-28 17:11:45 UTC (rev 28467)
@@ -1183,12 +1183,18 @@
        if(NO == [newFields isEqualToDictionary:oldFields]){
         [[[self undoManager] prepareWithInvocationTarget:self] 
setPubFields:oldFields];
                
+        if ([[self owner] isDocument])
+            [[BDSKCompletionManager sharedManager] 
removeCompletionsFromItems:@[self]];
+        
         [pubFields release];
         pubFields = [[NSMutableDictionary alloc] initWithDictionary:newFields];
         
         [self updateMetadataForKey:BDSKAllFieldsString];
 
-               NSDictionary *notifInfo = @{}; // cmh: maybe not the best info, 
but handled correctly
+        if ([[self owner] isDocument])
+            [[BDSKCompletionManager sharedManager] 
addCompletionsFromItems:@[self]];
+        
+        NSDictionary *notifInfo = @{}; // cmh: maybe not the best info, but 
handled correctly
                [[NSNotificationCenter defaultCenter] 
postNotificationName:BDSKBibItemChangedNotification
                                                                                
                                        object:self
                                                                                
                                  userInfo:notifInfo];
@@ -1214,15 +1220,27 @@
                                                                                
                                 toValue:oldValue
                                                                                
                         withModDate:[self dateModified]];
        }
-       
+    if ([[self owner] isDocument] && oldValue) {
+        // remove possibly erroneous value for completion
+        if ([key isPersonField])
+            [[BDSKCompletionManager sharedManager] 
removeNamesForCompletion:[self peopleArrayForField:key inherit:NO]];
+        else
+            [[BDSKCompletionManager sharedManager] removeString:oldValue 
forCompletionEntry:key];
+    }
+    
     [pubFields setValue:value forKey:key];
-    // to allow autocomplete:
-    if (value)
-               [[BDSKCompletionManager sharedManager] addString:value 
forCompletionEntry:key];
     [self setModifiedDate:date];
        [self updateMetadataForKey:key];
-       
+    
     if ([self owner]) {
+        if ([[self owner] isDocument] && value) {
+            // to allow autocomplete:
+            if ([key isPersonField])
+                [[BDSKCompletionManager sharedManager] 
addNamesForCompletion:[self peopleArrayForField:key inherit:NO]];
+            else
+                [[BDSKCompletionManager sharedManager] addString:value 
forCompletionEntry:key];
+        }
+
         NSMutableDictionary *notifInfo = [NSMutableDictionary 
dictionaryWithObjectsAndKeys:key, BDSKBibItemKeyKey, nil];
         [notifInfo setValue:value forKey:BDSKBibItemNewValueKey];
         [notifInfo setValue:oldValue forKey:BDSKBibItemOldValueKey];
@@ -4103,10 +4121,12 @@
     // parser doesn't allow empty cite keys
     BDSKPRECONDITION([NSString isEmptyString:newCiteKey] == NO);
     if(newCiteKey != citeKey){
+        if ([[self owner] isDocument] && [self hasEmptyOrDefaultCiteKey] == NO)
+                [[BDSKCompletionManager sharedManager] removeString:citeKey 
forCompletionEntry:BDSKCrossrefString];
         [citeKey autorelease];
         citeKey = [newCiteKey copy];
-        if ([newCiteKey isEqualToString:defaultCiteKey] == NO && [newCiteKey 
isEqualToString:placeholderCiteKey] == NO)
-            [[BDSKCompletionManager sharedManager] addString:newCiteKey 
forCompletionEntry:BDSKCrossrefString];
+        if ([[self owner] isDocument] && [self hasEmptyOrDefaultCiteKey] == NO)
+                [[BDSKCompletionManager sharedManager] addString:newCiteKey 
forCompletionEntry:BDSKCrossrefString];
     }
 }
 

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.



_______________________________________________
Bibdesk-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/bibdesk-commit

Reply via email to